From c91cda209a1e2467bbb5fbb5a3116757d38ef374 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Sun, 8 Jul 2012 18:04:56 -0400 Subject: Avoid libdl dependencies in bundled libverto The upstream libverto depends on dynamic loading and in particular on dladdr(), which is not universal. To avoid this dependency, stub out support for module loading (by replacing module.c) and instead integrate the k5ev module directly into the bundled verto library. This change removes the need to link, include, and invoke libverto differently depending on whether we're using the bundled library; we can always just link with -lverto and call verto_default(). bigredbutton: whitespace ticket: 7351 (new) --- src/config/pre.in | 5 +- src/configure.in | 7 +- src/lib/apputils/deps | 2 +- src/lib/apputils/net-server.c | 9 - src/util/Makefile.in | 2 +- src/util/depfix.pl | 1 - src/util/k5ev/Makefile.in | 52 - src/util/k5ev/README | 31 - src/util/k5ev/Symbols.ev | 73 - src/util/k5ev/deps | 7 - src/util/k5ev/ev.c | 3913 ----------------------------------- src/util/k5ev/ev.h | 829 -------- src/util/k5ev/ev_poll.c | 148 -- src/util/k5ev/ev_select.c | 310 --- src/util/k5ev/ev_vars.h | 203 -- src/util/k5ev/ev_win32.c | 153 -- src/util/k5ev/ev_wrap.h | 196 -- src/util/k5ev/libverto-k5ev.exports | 3 - src/util/k5ev/verto-k5ev.c | 215 -- src/util/k5ev/verto-k5ev.h | 33 - src/util/k5ev/verto-libev.c | 199 -- src/util/verto/Makefile.in | 22 +- src/util/verto/README | 40 +- src/util/verto/Symbols.ev | 73 + src/util/verto/deps | 4 + src/util/verto/ev.c | 3913 +++++++++++++++++++++++++++++++++++ src/util/verto/ev.h | 829 ++++++++ src/util/verto/ev_poll.c | 148 ++ src/util/verto/ev_select.c | 310 +++ src/util/verto/ev_vars.h | 203 ++ src/util/verto/ev_win32.c | 153 ++ src/util/verto/ev_wrap.h | 196 ++ src/util/verto/module.c | 179 +- src/util/verto/verto-k5ev.c | 212 ++ src/util/verto/verto-libev.c | 199 ++ 35 files changed, 6300 insertions(+), 6572 deletions(-) delete mode 100644 src/util/k5ev/Makefile.in delete mode 100644 src/util/k5ev/README delete mode 100644 src/util/k5ev/Symbols.ev delete mode 100644 src/util/k5ev/deps delete mode 100644 src/util/k5ev/ev.c delete mode 100644 src/util/k5ev/ev.h delete mode 100644 src/util/k5ev/ev_poll.c delete mode 100644 src/util/k5ev/ev_select.c delete mode 100644 src/util/k5ev/ev_vars.h delete mode 100644 src/util/k5ev/ev_win32.c delete mode 100644 src/util/k5ev/ev_wrap.h delete mode 100644 src/util/k5ev/libverto-k5ev.exports delete mode 100644 src/util/k5ev/verto-k5ev.c delete mode 100644 src/util/k5ev/verto-k5ev.h delete mode 100644 src/util/k5ev/verto-libev.c create mode 100644 src/util/verto/Symbols.ev create mode 100644 src/util/verto/ev.c create mode 100644 src/util/verto/ev.h create mode 100644 src/util/verto/ev_poll.c create mode 100644 src/util/verto/ev_select.c create mode 100644 src/util/verto/ev_vars.h create mode 100644 src/util/verto/ev_win32.c create mode 100644 src/util/verto/ev_wrap.h create mode 100644 src/util/verto/verto-k5ev.c create mode 100644 src/util/verto/verto-libev.c diff --git a/src/config/pre.in b/src/config/pre.in index e5a087c02c..1ba26d8502 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -369,9 +369,6 @@ VERTO_VERSION = @VERTO_VERSION@ VERTO_DEPS = $(VERTO_DEPS-@VERTO_VERSION@) VERTO_DEPS-sys = VERTO_DEPS-k5 = $(BUILDTOP)/include/verto.h -VERTO_K5EV_DEPS = $(VERTO_K5EV_DEPS-@VERTO_VERSION@) -VERTO_K5EV_DEPS-sys = -VERTO_K5EV_DEPS-k5 = $(BUILDTOP)/include/verto-k5ev.h # LIBS gets substituted in... e.g. -lnsl -lsocket @@ -389,7 +386,7 @@ KDB5_LIB = -lkdb5 $(KDB5_PLUGIN_LIBS) VERTO_DEPLIB = $(VERTO_DEPLIB-@VERTO_VERSION@) VERTO_DEPLIB-sys = # empty -VERTO_DEPLIB-k5 = $(TOPLIBD)/libverto-k5ev$(DEPLIBEXT) $(TOPLIBD)/libverto$(DEPLIBEXT) +VERTO_DEPLIB-k5 = $(TOPLIBD)/libverto$(DEPLIBEXT) VERTO_CFLAGS = @VERTO_CFLAGS@ VERTO_LIBS = @VERTO_LIBS@ diff --git a/src/configure.in b/src/configure.in index 9e9c94ff99..7154f686bd 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1219,7 +1219,7 @@ AC_ARG_WITH([system-verto], [AC_HELP_STRING([--with-system-verto], [always use system verto library])], [], [with_system_verto=default]) VERTO_CFLAGS= -VERTO_LIBS="-lverto-k5ev -lverto" +VERTO_LIBS="-lverto" VERTO_VERSION=k5 if test "x$with_system_verto" != xno; then if verto_cflags=`pkg-config --cflags libverto 2>&1`; then @@ -1227,7 +1227,7 @@ if test "x$with_system_verto" != xno; then VERTO_LIBS=`pkg-config --libs libverto` VERTO_VERSION=sys else - AC_CHECK_LIB([verto], [verto_run], [VERTO_VERSION=sys; VERTO_LIBS=-lverto], + AC_CHECK_LIB([verto], [verto_run], [VERTO_VERSION=sys], [if test "x$with_system_verto" = xyes; then AC_MSG_ERROR([cannot detect system libverto]) fi]) @@ -1237,7 +1237,6 @@ if test "x$VERTO_VERSION" = xsys; then AC_MSG_NOTICE([Using system libverto]) else AC_MSG_RESULT([Using built-in libverto]) - AC_DEFINE([INTERNAL_VERTO],[1],[Define if using bundled libverto]) fi AC_SUBST([VERTO_CFLAGS]) AC_SUBST([VERTO_LIBS]) @@ -1295,7 +1294,7 @@ AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config]) V5_AC_OUTPUT_MAKEFILE(. util util/support util/profile util/profile/testmod util/send-pr - util/verto util/k5ev + util/verto lib lib/kdb diff --git a/src/lib/apputils/deps b/src/lib/apputils/deps index 586e1ef767..a41563e78f 100644 --- a/src/lib/apputils/deps +++ b/src/lib/apputils/deps @@ -16,7 +16,7 @@ net-server.so net-server.po $(OUTPRE)net-server.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(COM_ERR_DEPS) $(VERTO_DEPS) $(VERTO_K5EV_DEPS) $(top_srcdir)/include/adm_proto.h \ + $(COM_ERR_DEPS) $(VERTO_DEPS) $(top_srcdir)/include/adm_proto.h \ $(top_srcdir)/include/fake-addrinfo.h $(top_srcdir)/include/foreachaddr.h \ $(top_srcdir)/include/gssrpc/auth.h $(top_srcdir)/include/gssrpc/auth_gss.h \ $(top_srcdir)/include/gssrpc/auth_unix.h $(top_srcdir)/include/gssrpc/clnt.h \ diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c index 0fd08eceea..1f8a8f97ae 100644 --- a/src/lib/apputils/net-server.c +++ b/src/lib/apputils/net-server.c @@ -58,10 +58,6 @@ #include "fake-addrinfo.h" #include "net-server.h" -#ifdef INTERNAL_VERTO -#include "verto-k5ev.h" -#endif - #include /* XXX */ @@ -269,12 +265,7 @@ loop_init(verto_ev_type types) types |= VERTO_EV_TYPE_IO; types |= VERTO_EV_TYPE_SIGNAL; types |= VERTO_EV_TYPE_TIMEOUT; - -#ifdef INTERNAL_VERTO - return verto_default_k5ev(); -#else return verto_default(NULL, types); -#endif } static void diff --git a/src/util/Makefile.in b/src/util/Makefile.in index f45bc70825..f2f6b75d1e 100644 --- a/src/util/Makefile.in +++ b/src/util/Makefile.in @@ -15,7 +15,7 @@ MAYBE_ET_sys = MAYBE_ET_intlsys = MAYBE_SS_sys = MAYBE_VERTO_sys = -MAYBE_VERTO_k5 = verto k5ev +MAYBE_VERTO_k5 = verto all-recurse: diff --git a/src/util/depfix.pl b/src/util/depfix.pl index 4fc37890bf..f648da8948 100644 --- a/src/util/depfix.pl +++ b/src/util/depfix.pl @@ -141,7 +141,6 @@ sub do_subs_2 { s;\$\(BUILDTOP\)/include/com_err.h ;\$(COM_ERR_DEPS) ;g; s;\$\(BUILDTOP\)/include/ss/ss.h \$\(BUILDTOP\)/include/ss/ss_err.h ;\$(SS_DEPS) ;g; s;\$\(BUILDTOP\)/include/db-config.h \$\(BUILDTOP\)/include/db.h ;\$(DB_DEPS) ;g; - s;\$\(BUILDTOP\)/include/verto-k5ev.h ;\$(VERTO_K5EV_DEPS) ;g; s;\$\(BUILDTOP\)/include/verto.h ;\$(VERTO_DEPS) ;g; if ($thisdir eq "util/gss-kernel-lib") { # Here com_err.h is used from the current directory. diff --git a/src/util/k5ev/Makefile.in b/src/util/k5ev/Makefile.in deleted file mode 100644 index b80a60dfb4..0000000000 --- a/src/util/k5ev/Makefile.in +++ /dev/null @@ -1,52 +0,0 @@ -mydir=util$(S)k5ev -BUILDTOP=$(REL)..$(S).. -RELDIR=../util/k5ev -DEFS= - -SED = sed - -LIBBASE=verto-k5ev -LIBMAJOR=0 -LIBMINOR=0 - -LOCALINCLUDES=-I. -I$(srcdir)/../verto - -# Turn off extra warnings since we're not going to clean up libev's code. -WARN_CFLAGS= - -STLIBOBJS=verto-k5ev.o -LIBOBJS=$(OUTPRE)verto-k5ev.$(OBJEXT) -SRCS=verto-k5ev.c - -STOBJLISTS=OBJS.ST -SHLIB_EXPLIBS= $(LIBS) -lverto -lm # libm needed for ceil() currently. -SHLIB_DIRS=-L$(TOPLIBD) -SHLIB_RDIRS=$(KRB5_LIBDIR) - -VERTO_K5EV_HDR=$(BUILDTOP)$(S)include$(S)verto-k5ev.h - -all-unix:: all-liblinks includes - -install-unix:: install-libs - -clean-unix:: clean-liblinks clean-libs clean-libobjs - $(RM) $(VERTO_K5EV_HDR) - -includes:: $(VERTO_K5EV_HDR) -depend:: $(VERTO_K5EV_HDR) - -$(VERTO_K5EV_HDR): $(srcdir)/verto-k5ev.h - $(RM) $@ - $(CP) $(srcdir)/verto-k5ev.h $@ - -rename.h: $(srcdir)/Symbols.ev - $(RM) $@ - $(SED) -e 's/.*/#define & k5&/' < $(srcdir)/Symbols.ev > $@ - -clean:: - $(RM) rename.h - -depend:: rename.h - -@lib_frag@ -@libobj_frag@ diff --git a/src/util/k5ev/README b/src/util/k5ev/README deleted file mode 100644 index 7a14f13274..0000000000 --- a/src/util/k5ev/README +++ /dev/null @@ -1,31 +0,0 @@ -This directory builds a private libverto module using an embedded -libev with renamed symbols (so we don't leak libev symbols into the -namespace on platforms where we can't control the export list). - -libev has built-in support for this kind of embedding, so we don't -have to modify the libev sources. Following libev's documentation, -the following files have been copied from the ev sources: - - ev.h - ev_vars.h - ev_wrap.h - ev.c - ev_select.c - ev_poll.c - ev_win32.c - Symbols.ev - -(Symbols.ev wasn't included in the 4.04 tar file due to an oversight, -so it is taken from the appropriate tag in libev's source repository.) - -To rename the exported symbols, we create rename.h from Symbols.ev. -We also use Symbols.ev to construct the library export list. -(Renaming libev's symbols would be unnecessary if libev's embedding -had support for making its API symbols static, but it currently does -not.) The source file verto-k5ev.c wraps ev.c with appropriate -embedding defines, and then defines the libverto module functions -using the slightly modified contents of libverto's verto-ev.c. - -The libev upstream project page is at: - - http://software.schmorp.de/pkg/libev.html diff --git a/src/util/k5ev/Symbols.ev b/src/util/k5ev/Symbols.ev deleted file mode 100644 index 7a29a75cba..0000000000 --- a/src/util/k5ev/Symbols.ev +++ /dev/null @@ -1,73 +0,0 @@ -ev_async_send -ev_async_start -ev_async_stop -ev_backend -ev_break -ev_check_start -ev_check_stop -ev_child_start -ev_child_stop -ev_cleanup_start -ev_cleanup_stop -ev_clear_pending -ev_default_loop -ev_default_loop_ptr -ev_depth -ev_embed_start -ev_embed_stop -ev_embed_sweep -ev_embeddable_backends -ev_feed_event -ev_feed_fd_event -ev_feed_signal -ev_feed_signal_event -ev_fork_start -ev_fork_stop -ev_idle_start -ev_idle_stop -ev_invoke -ev_invoke_pending -ev_io_start -ev_io_stop -ev_iteration -ev_loop_destroy -ev_loop_fork -ev_loop_new -ev_now -ev_now_update -ev_once -ev_pending_count -ev_periodic_again -ev_periodic_start -ev_periodic_stop -ev_prepare_start -ev_prepare_stop -ev_recommended_backends -ev_ref -ev_resume -ev_run -ev_set_allocator -ev_set_invoke_pending_cb -ev_set_io_collect_interval -ev_set_loop_release_cb -ev_set_syserr_cb -ev_set_timeout_collect_interval -ev_set_userdata -ev_signal_start -ev_signal_stop -ev_sleep -ev_stat_start -ev_stat_stat -ev_stat_stop -ev_supported_backends -ev_suspend -ev_time -ev_timer_again -ev_timer_remaining -ev_timer_start -ev_timer_stop -ev_unref -ev_userdata -ev_verify -ev_version_major -ev_version_minor diff --git a/src/util/k5ev/deps b/src/util/k5ev/deps deleted file mode 100644 index 5fd8552493..0000000000 --- a/src/util/k5ev/deps +++ /dev/null @@ -1,7 +0,0 @@ -# -# Generated makefile dependencies follow. -# -verto-k5ev.so verto-k5ev.po $(OUTPRE)verto-k5ev.$(OBJEXT): \ - $(BUILDTOP)/include/autoconf.h $(VERTO_DEPS) $(srcdir)/../verto/verto-module.h \ - ev.c ev.h ev_poll.c ev_select.c ev_vars.h ev_wrap.h \ - rename.h verto-k5ev.c verto-k5ev.h diff --git a/src/util/k5ev/ev.c b/src/util/k5ev/ev.c deleted file mode 100644 index 4187b18af7..0000000000 --- a/src/util/k5ev/ev.c +++ /dev/null @@ -1,3913 +0,0 @@ -/* - * libev event processing core, watcher management - * - * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -/* this big block deduces configuration from config.h */ -#ifndef EV_STANDALONE -# ifdef EV_CONFIG_H -# include EV_CONFIG_H -# else -# include "config.h" -# endif - -# if HAVE_CLOCK_SYSCALL -# ifndef EV_USE_CLOCK_SYSCALL -# define EV_USE_CLOCK_SYSCALL 1 -# ifndef EV_USE_REALTIME -# define EV_USE_REALTIME 0 -# endif -# ifndef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 1 -# endif -# endif -# elif !defined(EV_USE_CLOCK_SYSCALL) -# define EV_USE_CLOCK_SYSCALL 0 -# endif - -# if HAVE_CLOCK_GETTIME -# ifndef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 1 -# endif -# ifndef EV_USE_REALTIME -# define EV_USE_REALTIME 0 -# endif -# else -# ifndef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 0 -# endif -# ifndef EV_USE_REALTIME -# define EV_USE_REALTIME 0 -# endif -# endif - -# if HAVE_NANOSLEEP -# ifndef EV_USE_NANOSLEEP -# define EV_USE_NANOSLEEP EV_FEATURE_OS -# endif -# else -# undef EV_USE_NANOSLEEP -# define EV_USE_NANOSLEEP 0 -# endif - -# if HAVE_SELECT && HAVE_SYS_SELECT_H -# ifndef EV_USE_SELECT -# define EV_USE_SELECT EV_FEATURE_BACKENDS -# endif -# else -# undef EV_USE_SELECT -# define EV_USE_SELECT 0 -# endif - -# if HAVE_POLL && HAVE_POLL_H -# ifndef EV_USE_POLL -# define EV_USE_POLL EV_FEATURE_BACKENDS -# endif -# else -# undef EV_USE_POLL -# define EV_USE_POLL 0 -# endif - -# if HAVE_EPOLL_CTL && HAVE_SYS_EPOLL_H -# ifndef EV_USE_EPOLL -# define EV_USE_EPOLL EV_FEATURE_BACKENDS -# endif -# else -# undef EV_USE_EPOLL -# define EV_USE_EPOLL 0 -# endif - -# if HAVE_KQUEUE && HAVE_SYS_EVENT_H -# ifndef EV_USE_KQUEUE -# define EV_USE_KQUEUE EV_FEATURE_BACKENDS -# endif -# else -# undef EV_USE_KQUEUE -# define EV_USE_KQUEUE 0 -# endif - -# if HAVE_PORT_H && HAVE_PORT_CREATE -# ifndef EV_USE_PORT -# define EV_USE_PORT EV_FEATURE_BACKENDS -# endif -# else -# undef EV_USE_PORT -# define EV_USE_PORT 0 -# endif - -# if HAVE_INOTIFY_INIT && HAVE_SYS_INOTIFY_H -# ifndef EV_USE_INOTIFY -# define EV_USE_INOTIFY EV_FEATURE_OS -# endif -# else -# undef EV_USE_INOTIFY -# define EV_USE_INOTIFY 0 -# endif - -# if HAVE_SIGNALFD && HAVE_SYS_SIGNALFD_H -# ifndef EV_USE_SIGNALFD -# define EV_USE_SIGNALFD EV_FEATURE_OS -# endif -# else -# undef EV_USE_SIGNALFD -# define EV_USE_SIGNALFD 0 -# endif - -# if HAVE_EVENTFD -# ifndef EV_USE_EVENTFD -# define EV_USE_EVENTFD EV_FEATURE_OS -# endif -# else -# undef EV_USE_EVENTFD -# define EV_USE_EVENTFD 0 -# endif - -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#ifdef EV_H -# include EV_H -#else -# include "ev.h" -#endif - -EV_CPP(extern "C" {) - -#ifndef _WIN32 -# include -# include -# include -#else -# include -# define WIN32_LEAN_AND_MEAN -# include -# ifndef EV_SELECT_IS_WINSOCKET -# define EV_SELECT_IS_WINSOCKET 1 -# endif -# undef EV_AVOID_STDIO -#endif - -/* OS X, in its infinite idiocy, actually HARDCODES - * a limit of 1024 into their select. Where people have brains, - * OS X engineers apparently have a vacuum. Or maybe they were - * ordered to have a vacuum, or they do anything for money. - * This might help. Or not. - */ -#define _DARWIN_UNLIMITED_SELECT 1 - -/* this block tries to deduce configuration from header-defined symbols and defaults */ - -/* try to deduce the maximum number of signals on this platform */ -#if defined (EV_NSIG) -/* use what's provided */ -#elif defined (NSIG) -# define EV_NSIG (NSIG) -#elif defined(_NSIG) -# define EV_NSIG (_NSIG) -#elif defined (SIGMAX) -# define EV_NSIG (SIGMAX+1) -#elif defined (SIG_MAX) -# define EV_NSIG (SIG_MAX+1) -#elif defined (_SIG_MAX) -# define EV_NSIG (_SIG_MAX+1) -#elif defined (MAXSIG) -# define EV_NSIG (MAXSIG+1) -#elif defined (MAX_SIG) -# define EV_NSIG (MAX_SIG+1) -#elif defined (SIGARRAYSIZE) -# define EV_NSIG (SIGARRAYSIZE) /* Assume ary[SIGARRAYSIZE] */ -#elif defined (_sys_nsig) -# define EV_NSIG (_sys_nsig) /* Solaris 2.5 */ -#else -# error "unable to find value for NSIG, please report" -/* to make it compile regardless, just remove the above line, */ -/* but consider reporting it, too! :) */ -# define EV_NSIG 65 -#endif - -#ifndef EV_USE_CLOCK_SYSCALL -# if __linux && __GLIBC__ >= 2 -# define EV_USE_CLOCK_SYSCALL EV_FEATURE_OS -# else -# define EV_USE_CLOCK_SYSCALL 0 -# endif -#endif - -#ifndef EV_USE_MONOTONIC -# if defined (_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 -# define EV_USE_MONOTONIC EV_FEATURE_OS -# else -# define EV_USE_MONOTONIC 0 -# endif -#endif - -#ifndef EV_USE_REALTIME -# define EV_USE_REALTIME !EV_USE_CLOCK_SYSCALL -#endif - -#ifndef EV_USE_NANOSLEEP -# if _POSIX_C_SOURCE >= 199309L -# define EV_USE_NANOSLEEP EV_FEATURE_OS -# else -# define EV_USE_NANOSLEEP 0 -# endif -#endif - -#ifndef EV_USE_SELECT -# define EV_USE_SELECT EV_FEATURE_BACKENDS -#endif - -#ifndef EV_USE_POLL -# ifdef _WIN32 -# define EV_USE_POLL 0 -# else -# define EV_USE_POLL EV_FEATURE_BACKENDS -# endif -#endif - -#ifndef EV_USE_EPOLL -# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4)) -# define EV_USE_EPOLL EV_FEATURE_BACKENDS -# else -# define EV_USE_EPOLL 0 -# endif -#endif - -#ifndef EV_USE_KQUEUE -# define EV_USE_KQUEUE 0 -#endif - -#ifndef EV_USE_PORT -# define EV_USE_PORT 0 -#endif - -#ifndef EV_USE_INOTIFY -# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4)) -# define EV_USE_INOTIFY EV_FEATURE_OS -# else -# define EV_USE_INOTIFY 0 -# endif -#endif - -#ifndef EV_PID_HASHSIZE -# define EV_PID_HASHSIZE EV_FEATURE_DATA ? 16 : 1 -#endif - -#ifndef EV_INOTIFY_HASHSIZE -# define EV_INOTIFY_HASHSIZE EV_FEATURE_DATA ? 16 : 1 -#endif - -#ifndef EV_USE_EVENTFD -# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) -# define EV_USE_EVENTFD EV_FEATURE_OS -# else -# define EV_USE_EVENTFD 0 -# endif -#endif - -#ifndef EV_USE_SIGNALFD -# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) -# define EV_USE_SIGNALFD EV_FEATURE_OS -# else -# define EV_USE_SIGNALFD 0 -# endif -#endif - -#if 0 /* debugging */ -# define EV_VERIFY 3 -# define EV_USE_4HEAP 1 -# define EV_HEAP_CACHE_AT 1 -#endif - -#ifndef EV_VERIFY -# define EV_VERIFY (EV_FEATURE_API ? 1 : 0) -#endif - -#ifndef EV_USE_4HEAP -# define EV_USE_4HEAP EV_FEATURE_DATA -#endif - -#ifndef EV_HEAP_CACHE_AT -# define EV_HEAP_CACHE_AT EV_FEATURE_DATA -#endif - -/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ -/* which makes programs even slower. might work on other unices, too. */ -#if EV_USE_CLOCK_SYSCALL -# include -# ifdef SYS_clock_gettime -# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) -# undef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 1 -# else -# undef EV_USE_CLOCK_SYSCALL -# define EV_USE_CLOCK_SYSCALL 0 -# endif -#endif - -/* this block fixes any misconfiguration where we know we run into trouble otherwise */ - -#ifdef _AIX -/* AIX has a completely broken poll.h header */ -# undef EV_USE_POLL -# define EV_USE_POLL 0 -#endif - -#ifndef CLOCK_MONOTONIC -# undef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 0 -#endif - -#ifndef CLOCK_REALTIME -# undef EV_USE_REALTIME -# define EV_USE_REALTIME 0 -#endif - -#if !EV_STAT_ENABLE -# undef EV_USE_INOTIFY -# define EV_USE_INOTIFY 0 -#endif - -#if !EV_USE_NANOSLEEP -/* hp-ux has it in sys/time.h, which we unconditionally include above */ -# if !defined(_WIN32) && !defined(__hpux) -# include -# endif -#endif - -#if EV_USE_INOTIFY -# include -# include -/* some very old inotify.h headers don't have IN_DONT_FOLLOW */ -# ifndef IN_DONT_FOLLOW -# undef EV_USE_INOTIFY -# define EV_USE_INOTIFY 0 -# endif -#endif - -#if EV_SELECT_IS_WINSOCKET -# include -#endif - -#if EV_USE_EVENTFD -/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ -# include -# ifndef EFD_NONBLOCK -# define EFD_NONBLOCK O_NONBLOCK -# endif -# ifndef EFD_CLOEXEC -# ifdef O_CLOEXEC -# define EFD_CLOEXEC O_CLOEXEC -# else -# define EFD_CLOEXEC 02000000 -# endif -# endif -EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags); -#endif - -#if EV_USE_SIGNALFD -/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ -# include -# ifndef SFD_NONBLOCK -# define SFD_NONBLOCK O_NONBLOCK -# endif -# ifndef SFD_CLOEXEC -# ifdef O_CLOEXEC -# define SFD_CLOEXEC O_CLOEXEC -# else -# define SFD_CLOEXEC 02000000 -# endif -# endif -EV_CPP (extern "C") int signalfd (int fd, const sigset_t *mask, int flags); - -struct signalfd_siginfo -{ - uint32_t ssi_signo; - char pad[128 - sizeof (uint32_t)]; -}; -#endif - -/**/ - -#if EV_VERIFY >= 3 -# define EV_FREQUENT_CHECK ev_verify (EV_A) -#else -# define EV_FREQUENT_CHECK do { } while (0) -#endif - -/* - * This is used to avoid floating point rounding problems. - * It is added to ev_rt_now when scheduling periodics - * to ensure progress, time-wise, even when rounding - * errors are against us. - * This value is good at least till the year 4000. - * Better solutions welcome. - */ -#define TIME_EPSILON 0.0001220703125 /* 1/8192 */ - -#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */ -#define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */ - -#define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec = (long)((t - tv.tv_sec) * 1e6); } while (0) -#define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec = (long)((t - ts.tv_sec) * 1e9); } while (0) - -#if __GNUC__ >= 4 -# define expect(expr,value) __builtin_expect ((expr),(value)) -# define noinline __attribute__ ((noinline)) -#else -# define expect(expr,value) (expr) -# define noinline -# if __STDC_VERSION__ < 199901L && __GNUC__ < 2 -# define inline -# endif -#endif - -#define expect_false(expr) expect ((expr) != 0, 0) -#define expect_true(expr) expect ((expr) != 0, 1) -#define inline_size static inline - -#if EV_FEATURE_CODE -# define inline_speed static inline -#else -# define inline_speed static noinline -#endif - -#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) - -#if EV_MINPRI == EV_MAXPRI -# define ABSPRI(w) (((W)w), 0) -#else -# define ABSPRI(w) (((W)w)->priority - EV_MINPRI) -#endif - -#define EMPTY /* required for microsofts broken pseudo-c compiler */ -#define EMPTY2(a,b) /* used to suppress some warnings */ - -typedef ev_watcher *W; -typedef ev_watcher_list *WL; -typedef ev_watcher_time *WT; - -#define ev_active(w) ((W)(w))->active -#define ev_at(w) ((WT)(w))->at - -#if EV_USE_REALTIME -/* sig_atomic_t is used to avoid per-thread variables or locking but still */ -/* giving it a reasonably high chance of working on typical architectures */ -static EV_ATOMIC_T have_realtime; /* did clock_gettime (CLOCK_REALTIME) work? */ -#endif - -#if EV_USE_MONOTONIC -static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */ -#endif - -#ifndef EV_FD_TO_WIN32_HANDLE -# define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd) -#endif -#ifndef EV_WIN32_HANDLE_TO_FD -# define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0) -#endif -#ifndef EV_WIN32_CLOSE_FD -# define EV_WIN32_CLOSE_FD(fd) close (fd) -#endif - -#ifdef _WIN32 -# include "ev_win32.c" -#endif - -/*****************************************************************************/ - -#ifdef __linux -# include -#endif - -static unsigned int noinline -ev_linux_version (void) -{ -#ifdef __linux - unsigned int v = 0; - struct utsname buf; - int i; - char *p = buf.release; - - if (uname (&buf)) - return 0; - - for (i = 3+1; --i; ) - { - unsigned int c = 0; - - for (;;) - { - if (*p >= '0' && *p <= '9') - c = c * 10 + *p++ - '0'; - else - { - p += *p == '.'; - break; - } - } - - v = (v << 8) | c; - } - - return v; -#else - return 0; -#endif -} - -/*****************************************************************************/ - -#if EV_AVOID_STDIO -static void noinline -ev_printerr (const char *msg) -{ - write (STDERR_FILENO, msg, strlen (msg)); -} -#endif - -static void (*syserr_cb)(const char *msg); - -void -ev_set_syserr_cb (void (*cb)(const char *msg)) -{ - syserr_cb = cb; -} - -static void noinline -ev_syserr (const char *msg) -{ - if (!msg) - msg = "(libev) system error"; - - if (syserr_cb) - syserr_cb (msg); - else - { -#if EV_AVOID_STDIO - ev_printerr (msg); - ev_printerr (": "); - ev_printerr (strerror (errno)); - ev_printerr ("\n"); -#else - perror (msg); -#endif - abort (); - } -} - -static void * -ev_realloc_emul (void *ptr, long size) -{ -#if __GLIBC__ - return realloc (ptr, size); -#else - /* some systems, notably openbsd and darwin, fail to properly - * implement realloc (x, 0) (as required by both ansi c-89 and - * the single unix specification, so work around them here. - */ - - if (size) - return realloc (ptr, size); - - free (ptr); - return 0; -#endif -} - -static void *(*alloc)(void *ptr, long size) = ev_realloc_emul; - -void -ev_set_allocator (void *(*cb)(void *ptr, long size)) -{ - alloc = cb; -} - -inline_speed void * -ev_realloc (void *ptr, long size) -{ - ptr = alloc (ptr, size); - - if (!ptr && size) - { -#if EV_AVOID_STDIO - ev_printerr ("(libev) memory allocation failed, aborting.\n"); -#else - fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size); -#endif - abort (); - } - - return ptr; -} - -#define ev_malloc(size) ev_realloc (0, (size)) -#define ev_free(ptr) ev_realloc ((ptr), 0) - -/*****************************************************************************/ - -/* set in reify when reification needed */ -#define EV_ANFD_REIFY 1 - -/* file descriptor info structure */ -typedef struct -{ - WL head; - unsigned char events; /* the events watched for */ - unsigned char reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) */ - unsigned char emask; /* the epoll backend stores the actual kernel mask in here */ - unsigned char unused; -#if EV_USE_EPOLL - unsigned int egen; /* generation counter to counter epoll bugs */ -#endif -#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP - SOCKET handle; -#endif -#if EV_USE_IOCP - OVERLAPPED or, ow; -#endif -} ANFD; - -/* stores the pending event set for a given watcher */ -typedef struct -{ - W w; - int events; /* the pending event set for the given watcher */ -} ANPENDING; - -#if EV_USE_INOTIFY -/* hash table entry per inotify-id */ -typedef struct -{ - WL head; -} ANFS; -#endif - -/* Heap Entry */ -#if EV_HEAP_CACHE_AT - /* a heap element */ - typedef struct { - ev_tstamp at; - WT w; - } ANHE; - - #define ANHE_w(he) (he).w /* access watcher, read-write */ - #define ANHE_at(he) (he).at /* access cached at, read-only */ - #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */ -#else - /* a heap element */ - typedef WT ANHE; - - #define ANHE_w(he) (he) - #define ANHE_at(he) (he)->at - #define ANHE_at_cache(he) -#endif - -#if EV_MULTIPLICITY - - struct ev_loop - { - ev_tstamp ev_rt_now; - #define ev_rt_now ((loop)->ev_rt_now) - #define VAR(name,decl) decl; - #include "ev_vars.h" - #undef VAR - }; - #include "ev_wrap.h" - - static struct ev_loop default_loop_struct; - struct ev_loop *ev_default_loop_ptr; - -#else - - ev_tstamp ev_rt_now; - #define VAR(name,decl) static decl; - #include "ev_vars.h" - #undef VAR - - static int ev_default_loop_ptr; - -#endif - -#if EV_FEATURE_API -# define EV_RELEASE_CB if (expect_false (release_cb)) release_cb (EV_A) -# define EV_ACQUIRE_CB if (expect_false (acquire_cb)) acquire_cb (EV_A) -# define EV_INVOKE_PENDING invoke_cb (EV_A) -#else -# define EV_RELEASE_CB (void)0 -# define EV_ACQUIRE_CB (void)0 -# define EV_INVOKE_PENDING ev_invoke_pending (EV_A) -#endif - -#define EVBREAK_RECURSE 0x80 - -/*****************************************************************************/ - -#ifndef EV_HAVE_EV_TIME -ev_tstamp -ev_time (void) -{ -#if EV_USE_REALTIME - if (expect_true (have_realtime)) - { - struct timespec ts; - clock_gettime (CLOCK_REALTIME, &ts); - return ts.tv_sec + ts.tv_nsec * 1e-9; - } -#endif - - struct timeval tv; - gettimeofday (&tv, 0); - return tv.tv_sec + tv.tv_usec * 1e-6; -} -#endif - -inline_size ev_tstamp -get_clock (void) -{ -#if EV_USE_MONOTONIC - if (expect_true (have_monotonic)) - { - struct timespec ts; - clock_gettime (CLOCK_MONOTONIC, &ts); - return ts.tv_sec + ts.tv_nsec * 1e-9; - } -#endif - - return ev_time (); -} - -#if EV_MULTIPLICITY -ev_tstamp -ev_now (EV_P) -{ - return ev_rt_now; -} -#endif - -void -ev_sleep (ev_tstamp delay) -{ - if (delay > 0.) - { -#if EV_USE_NANOSLEEP - struct timespec ts; - - EV_TS_SET (ts, delay); - nanosleep (&ts, 0); -#elif defined(_WIN32) - Sleep ((unsigned long)(delay * 1e3)); -#else - struct timeval tv; - - /* here we rely on sys/time.h + sys/types.h + unistd.h providing select */ - /* something not guaranteed by newer posix versions, but guaranteed */ - /* by older ones */ - EV_TV_SET (tv, delay); - select (0, 0, 0, 0, &tv); -#endif - } -} - -inline_speed int -ev_timeout_to_ms (ev_tstamp timeout) -{ - int ms = timeout * 1000. + .999999; - - return expect_true (ms) ? ms : timeout < 1e-6 ? 0 : 1; -} - -/*****************************************************************************/ - -#define MALLOC_ROUND 4096 /* prefer to allocate in chunks of this size, must be 2**n and >> 4 longs */ - -/* find a suitable new size for the given array, */ -/* hopefully by rounding to a nice-to-malloc size */ -inline_size int -array_nextsize (int elem, int cur, int cnt) -{ - int ncur = cur + 1; - - do - ncur <<= 1; - while (cnt > ncur); - - /* if size is large, round to MALLOC_ROUND - 4 * longs to accomodate malloc overhead */ - if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4) - { - ncur *= elem; - ncur = (ncur + elem + (MALLOC_ROUND - 1) + sizeof (void *) * 4) & ~(MALLOC_ROUND - 1); - ncur = ncur - sizeof (void *) * 4; - ncur /= elem; - } - - return ncur; -} - -static noinline void * -array_realloc (int elem, void *base, int *cur, int cnt) -{ - *cur = array_nextsize (elem, *cur, cnt); - return ev_realloc (base, elem * *cur); -} - -#define array_init_zero(base,count) \ - memset ((void *)(base), 0, sizeof (*(base)) * (count)) - -#define array_needsize(type,base,cur,cnt,init) \ - if (expect_false ((cnt) > (cur))) \ - { \ - int ocur_ = (cur); \ - (base) = (type *)array_realloc \ - (sizeof (type), (base), &(cur), (cnt)); \ - init ((base) + (ocur_), (cur) - ocur_); \ - } - -#if 0 -#define array_slim(type,stem) \ - if (stem ## max < array_roundsize (stem ## cnt >> 2)) \ - { \ - stem ## max = array_roundsize (stem ## cnt >> 1); \ - base = (type *)ev_realloc (base, sizeof (type) * (stem ## max));\ - fprintf (stderr, "slimmed down " # stem " to %d\n", stem ## max);/*D*/\ - } -#endif - -#define array_free(stem, idx) \ - ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0; stem ## s idx = 0 - -/*****************************************************************************/ - -/* dummy callback for pending events */ -static void noinline -pendingcb (EV_P_ ev_prepare *w, int revents) -{ -} - -void noinline -ev_feed_event (EV_P_ void *w, int revents) -{ - W w_ = (W)w; - int pri = ABSPRI (w_); - - if (expect_false (w_->pending)) - pendings [pri][w_->pending - 1].events |= revents; - else - { - w_->pending = ++pendingcnt [pri]; - array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2); - pendings [pri][w_->pending - 1].w = w_; - pendings [pri][w_->pending - 1].events = revents; - } -} - -inline_speed void -feed_reverse (EV_P_ W w) -{ - array_needsize (W, rfeeds, rfeedmax, rfeedcnt + 1, EMPTY2); - rfeeds [rfeedcnt++] = w; -} - -inline_size void -feed_reverse_done (EV_P_ int revents) -{ - do - ev_feed_event (EV_A_ rfeeds [--rfeedcnt], revents); - while (rfeedcnt); -} - -inline_speed void -queue_events (EV_P_ W *events, int eventcnt, int type) -{ - int i; - - for (i = 0; i < eventcnt; ++i) - ev_feed_event (EV_A_ events [i], type); -} - -/*****************************************************************************/ - -inline_speed void -fd_event_nocheck (EV_P_ int fd, int revents) -{ - ANFD *anfd = anfds + fd; - ev_io *w; - - for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next) - { - int ev = w->events & revents; - - if (ev) - ev_feed_event (EV_A_ (W)w, ev); - } -} - -/* do not submit kernel events for fds that have reify set */ -/* because that means they changed while we were polling for new events */ -inline_speed void -fd_event (EV_P_ int fd, int revents) -{ - ANFD *anfd = anfds + fd; - - if (expect_true (!anfd->reify)) - fd_event_nocheck (EV_A_ fd, revents); -} - -void -ev_feed_fd_event (EV_P_ int fd, int revents) -{ - if (fd >= 0 && fd < anfdmax) - fd_event_nocheck (EV_A_ fd, revents); -} - -/* make sure the external fd watch events are in-sync */ -/* with the kernel/libev internal state */ -inline_size void -fd_reify (EV_P) -{ - int i; - -#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP - for (i = 0; i < fdchangecnt; ++i) - { - int fd = fdchanges [i]; - ANFD *anfd = anfds + fd; - - if (anfd->reify & EV__IOFDSET) - { - SOCKET handle = EV_FD_TO_WIN32_HANDLE (fd); - - if (handle != anfd->handle) - { - unsigned long arg; - - assert (("libev: only socket fds supported in this configuration", ioctlsocket (handle, FIONREAD, &arg) == 0)); - - /* handle changed, but fd didn't - we need to do it in two steps */ - backend_modify (EV_A_ fd, anfd->events, 0); - anfd->events = 0; - anfd->handle = handle; - } - } - } -#endif - - for (i = 0; i < fdchangecnt; ++i) - { - int fd = fdchanges [i]; - ANFD *anfd = anfds + fd; - ev_io *w; - - unsigned char o_events = anfd->events; - unsigned char o_reify = anfd->reify; - - anfd->reify = 0; - - /*if (expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */ - { - anfd->events = 0; - - for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next) - anfd->events |= (unsigned char)w->events; - - if (o_events != anfd->events) - o_reify = EV__IOFDSET; /* actually |= */ - } - - if (o_reify & EV__IOFDSET) - backend_modify (EV_A_ fd, o_events, anfd->events); - } - - fdchangecnt = 0; -} - -/* something about the given fd changed */ -inline_size void -fd_change (EV_P_ int fd, int flags) -{ - unsigned char reify = anfds [fd].reify; - anfds [fd].reify |= flags; - - if (expect_true (!reify)) - { - ++fdchangecnt; - array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2); - fdchanges [fdchangecnt - 1] = fd; - } -} - -/* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */ -inline_speed void -fd_kill (EV_P_ int fd) -{ - ev_io *w; - - while ((w = (ev_io *)anfds [fd].head)) - { - ev_io_stop (EV_A_ w); - ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE); - } -} - -/* check whether the given fd is actually valid, for error recovery */ -inline_size int -fd_valid (int fd) -{ -#ifdef _WIN32 - return EV_FD_TO_WIN32_HANDLE (fd) != -1; -#else - return fcntl (fd, F_GETFD) != -1; -#endif -} - -/* called on EBADF to verify fds */ -static void noinline -fd_ebadf (EV_P) -{ - int fd; - - for (fd = 0; fd < anfdmax; ++fd) - if (anfds [fd].events) - if (!fd_valid (fd) && errno == EBADF) - fd_kill (EV_A_ fd); -} - -/* called on ENOMEM in select/poll to kill some fds and retry */ -static void noinline -fd_enomem (EV_P) -{ - int fd; - - for (fd = anfdmax; fd--; ) - if (anfds [fd].events) - { - fd_kill (EV_A_ fd); - break; - } -} - -/* usually called after fork if backend needs to re-arm all fds from scratch */ -static void noinline -fd_rearm_all (EV_P) -{ - int fd; - - for (fd = 0; fd < anfdmax; ++fd) - if (anfds [fd].events) - { - anfds [fd].events = 0; - anfds [fd].emask = 0; - fd_change (EV_A_ fd, EV__IOFDSET | EV_ANFD_REIFY); - } -} - -/* used to prepare libev internal fd's */ -/* this is not fork-safe */ -inline_speed void -fd_intern (int fd) -{ -#ifdef _WIN32 - unsigned long arg = 1; - ioctlsocket (EV_FD_TO_WIN32_HANDLE (fd), FIONBIO, &arg); -#else - fcntl (fd, F_SETFD, FD_CLOEXEC); - fcntl (fd, F_SETFL, O_NONBLOCK); -#endif -} - -/*****************************************************************************/ - -/* - * the heap functions want a real array index. array index 0 is guaranteed to not - * be in-use at any time. the first heap entry is at array [HEAP0]. DHEAP gives - * the branching factor of the d-tree. - */ - -/* - * at the moment we allow libev the luxury of two heaps, - * a small-code-size 2-heap one and a ~1.5kb larger 4-heap - * which is more cache-efficient. - * the difference is about 5% with 50000+ watchers. - */ -#if EV_USE_4HEAP - -#define DHEAP 4 -#define HEAP0 (DHEAP - 1) /* index of first element in heap */ -#define HPARENT(k) ((((k) - HEAP0 - 1) / DHEAP) + HEAP0) -#define UPHEAP_DONE(p,k) ((p) == (k)) - -/* away from the root */ -inline_speed void -downheap (ANHE *heap, int N, int k) -{ - ANHE he = heap [k]; - ANHE *E = heap + N + HEAP0; - - for (;;) - { - ev_tstamp minat; - ANHE *minpos; - ANHE *pos = heap + DHEAP * (k - HEAP0) + HEAP0 + 1; - - /* find minimum child */ - if (expect_true (pos + DHEAP - 1 < E)) - { - /* fast path */ (minpos = pos + 0), (minat = ANHE_at (*minpos)); - if ( ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos)); - if ( ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos)); - if ( ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos)); - } - else if (pos < E) - { - /* slow path */ (minpos = pos + 0), (minat = ANHE_at (*minpos)); - if (pos + 1 < E && ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos)); - if (pos + 2 < E && ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos)); - if (pos + 3 < E && ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos)); - } - else - break; - - if (ANHE_at (he) <= minat) - break; - - heap [k] = *minpos; - ev_active (ANHE_w (*minpos)) = k; - - k = minpos - heap; - } - - heap [k] = he; - ev_active (ANHE_w (he)) = k; -} - -#else /* 4HEAP */ - -#define HEAP0 1 -#define HPARENT(k) ((k) >> 1) -#define UPHEAP_DONE(p,k) (!(p)) - -/* away from the root */ -inline_speed void -downheap (ANHE *heap, int N, int k) -{ - ANHE he = heap [k]; - - for (;;) - { - int c = k << 1; - - if (c >= N + HEAP0) - break; - - c += c + 1 < N + HEAP0 && ANHE_at (heap [c]) > ANHE_at (heap [c + 1]) - ? 1 : 0; - - if (ANHE_at (he) <= ANHE_at (heap [c])) - break; - - heap [k] = heap [c]; - ev_active (ANHE_w (heap [k])) = k; - - k = c; - } - - heap [k] = he; - ev_active (ANHE_w (he)) = k; -} -#endif - -/* towards the root */ -inline_speed void -upheap (ANHE *heap, int k) -{ - ANHE he = heap [k]; - - for (;;) - { - int p = HPARENT (k); - - if (UPHEAP_DONE (p, k) || ANHE_at (heap [p]) <= ANHE_at (he)) - break; - - heap [k] = heap [p]; - ev_active (ANHE_w (heap [k])) = k; - k = p; - } - - heap [k] = he; - ev_active (ANHE_w (he)) = k; -} - -/* move an element suitably so it is in a correct place */ -inline_size void -adjustheap (ANHE *heap, int N, int k) -{ - if (k > HEAP0 && ANHE_at (heap [k]) <= ANHE_at (heap [HPARENT (k)])) - upheap (heap, k); - else - downheap (heap, N, k); -} - -/* rebuild the heap: this function is used only once and executed rarely */ -inline_size void -reheap (ANHE *heap, int N) -{ - int i; - - /* we don't use floyds algorithm, upheap is simpler and is more cache-efficient */ - /* also, this is easy to implement and correct for both 2-heaps and 4-heaps */ - for (i = 0; i < N; ++i) - upheap (heap, i + HEAP0); -} - -/*****************************************************************************/ - -/* associate signal watchers to a signal signal */ -typedef struct -{ - EV_ATOMIC_T pending; -#if EV_MULTIPLICITY - EV_P; -#endif - WL head; -} ANSIG; - -static ANSIG signals [EV_NSIG - 1]; - -/*****************************************************************************/ - -#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE - -static void noinline -evpipe_init (EV_P) -{ - if (!ev_is_active (&pipe_w)) - { -# if EV_USE_EVENTFD - evfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC); - if (evfd < 0 && errno == EINVAL) - evfd = eventfd (0, 0); - - if (evfd >= 0) - { - evpipe [0] = -1; - fd_intern (evfd); /* doing it twice doesn't hurt */ - ev_io_set (&pipe_w, evfd, EV_READ); - } - else -# endif - { - while (pipe (evpipe)) - ev_syserr ("(libev) error creating signal/async pipe"); - - fd_intern (evpipe [0]); - fd_intern (evpipe [1]); - ev_io_set (&pipe_w, evpipe [0], EV_READ); - } - - ev_io_start (EV_A_ &pipe_w); - ev_unref (EV_A); /* watcher should not keep loop alive */ - } -} - -inline_size void -evpipe_write (EV_P_ EV_ATOMIC_T *flag) -{ - if (!*flag) - { - int old_errno = errno; /* save errno because write might clobber it */ - char dummy; - - *flag = 1; - -#if EV_USE_EVENTFD - if (evfd >= 0) - { - uint64_t counter = 1; - write (evfd, &counter, sizeof (uint64_t)); - } - else -#endif - /* win32 people keep sending patches that change this write() to send() */ - /* and then run away. but send() is wrong, it wants a socket handle on win32 */ - /* so when you think this write should be a send instead, please find out */ - /* where your send() is from - it's definitely not the microsoft send, and */ - /* tell me. thank you. */ - write (evpipe [1], &dummy, 1); - - errno = old_errno; - } -} - -/* called whenever the libev signal pipe */ -/* got some events (signal, async) */ -static void -pipecb (EV_P_ ev_io *iow, int revents) -{ - int i; - -#if EV_USE_EVENTFD - if (evfd >= 0) - { - uint64_t counter; - read (evfd, &counter, sizeof (uint64_t)); - } - else -#endif - { - char dummy; - /* see discussion in evpipe_write when you think this read should be recv in win32 */ - read (evpipe [0], &dummy, 1); - } - -#if EV_SIGNAL_ENABLE - if (sig_pending) - { - sig_pending = 0; - - for (i = EV_NSIG - 1; i--; ) - if (expect_false (signals [i].pending)) - ev_feed_signal_event (EV_A_ i + 1); - } -#endif - -#if EV_ASYNC_ENABLE - if (async_pending) - { - async_pending = 0; - - for (i = asynccnt; i--; ) - if (asyncs [i]->sent) - { - asyncs [i]->sent = 0; - ev_feed_event (EV_A_ asyncs [i], EV_ASYNC); - } - } -#endif -} - -/*****************************************************************************/ - -void -ev_feed_signal (int signum) -{ -#if EV_MULTIPLICITY - EV_P = signals [signum - 1].loop; - - if (!EV_A) - return; -#endif - - signals [signum - 1].pending = 1; - evpipe_write (EV_A_ &sig_pending); -} - -static void -ev_sighandler (int signum) -{ -#ifdef _WIN32 - signal (signum, ev_sighandler); -#endif - - ev_feed_signal (signum); -} - -void noinline -ev_feed_signal_event (EV_P_ int signum) -{ - WL w; - - if (expect_false (signum <= 0 || signum > EV_NSIG)) - return; - - --signum; - -#if EV_MULTIPLICITY - /* it is permissible to try to feed a signal to the wrong loop */ - /* or, likely more useful, feeding a signal nobody is waiting for */ - - if (expect_false (signals [signum].loop != EV_A)) - return; -#endif - - signals [signum].pending = 0; - - for (w = signals [signum].head; w; w = w->next) - ev_feed_event (EV_A_ (W)w, EV_SIGNAL); -} - -#if EV_USE_SIGNALFD -static void -sigfdcb (EV_P_ ev_io *iow, int revents) -{ - struct signalfd_siginfo si[2], *sip; /* these structs are big */ - - for (;;) - { - ssize_t res = read (sigfd, si, sizeof (si)); - - /* not ISO-C, as res might be -1, but works with SuS */ - for (sip = si; (char *)sip < (char *)si + res; ++sip) - ev_feed_signal_event (EV_A_ sip->ssi_signo); - - if (res < (ssize_t)sizeof (si)) - break; - } -} -#endif - -#endif - -/*****************************************************************************/ - -#if EV_CHILD_ENABLE -static WL childs [EV_PID_HASHSIZE]; - -static ev_signal childev; - -#ifndef WIFCONTINUED -# define WIFCONTINUED(status) 0 -#endif - -/* handle a single child status event */ -inline_speed void -child_reap (EV_P_ int chain, int pid, int status) -{ - ev_child *w; - int traced = WIFSTOPPED (status) || WIFCONTINUED (status); - - for (w = (ev_child *)childs [chain & ((EV_PID_HASHSIZE) - 1)]; w; w = (ev_child *)((WL)w)->next) - { - if ((w->pid == pid || !w->pid) - && (!traced || (w->flags & 1))) - { - ev_set_priority (w, EV_MAXPRI); /* need to do it *now*, this *must* be the same prio as the signal watcher itself */ - w->rpid = pid; - w->rstatus = status; - ev_feed_event (EV_A_ (W)w, EV_CHILD); - } - } -} - -#ifndef WCONTINUED -# define WCONTINUED 0 -#endif - -/* called on sigchld etc., calls waitpid */ -static void -childcb (EV_P_ ev_signal *sw, int revents) -{ - int pid, status; - - /* some systems define WCONTINUED but then fail to support it (linux 2.4) */ - if (0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED))) - if (!WCONTINUED - || errno != EINVAL - || 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED))) - return; - - /* make sure we are called again until all children have been reaped */ - /* we need to do it this way so that the callback gets called before we continue */ - ev_feed_event (EV_A_ (W)sw, EV_SIGNAL); - - child_reap (EV_A_ pid, pid, status); - if ((EV_PID_HASHSIZE) > 1) - child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */ -} - -#endif - -/*****************************************************************************/ - -#if EV_USE_IOCP -# include "ev_iocp.c" -#endif -#if EV_USE_PORT -# include "ev_port.c" -#endif -#if EV_USE_KQUEUE -# include "ev_kqueue.c" -#endif -#if EV_USE_EPOLL -# include "ev_epoll.c" -#endif -#if EV_USE_POLL -# include "ev_poll.c" -#endif -#if EV_USE_SELECT -# include "ev_select.c" -#endif - -int -ev_version_major (void) -{ - return EV_VERSION_MAJOR; -} - -int -ev_version_minor (void) -{ - return EV_VERSION_MINOR; -} - -/* return true if we are running with elevated privileges and should ignore env variables */ -int inline_size -enable_secure (void) -{ -#ifdef _WIN32 - return 0; -#else - return getuid () != geteuid () - || getgid () != getegid (); -#endif -} - -unsigned int -ev_supported_backends (void) -{ - unsigned int flags = 0; - - if (EV_USE_PORT ) flags |= EVBACKEND_PORT; - if (EV_USE_KQUEUE) flags |= EVBACKEND_KQUEUE; - if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL; - if (EV_USE_POLL ) flags |= EVBACKEND_POLL; - if (EV_USE_SELECT) flags |= EVBACKEND_SELECT; - - return flags; -} - -unsigned int -ev_recommended_backends (void) -{ - unsigned int flags = ev_supported_backends (); - -#ifndef __NetBSD__ - /* kqueue is borked on everything but netbsd apparently */ - /* it usually doesn't work correctly on anything but sockets and pipes */ - flags &= ~EVBACKEND_KQUEUE; -#endif -#ifdef __APPLE__ - /* only select works correctly on that "unix-certified" platform */ - flags &= ~EVBACKEND_KQUEUE; /* horribly broken, even for sockets */ - flags &= ~EVBACKEND_POLL; /* poll is based on kqueue from 10.5 onwards */ -#endif -#ifdef __FreeBSD__ - flags &= ~EVBACKEND_POLL; /* poll return value is unusable (http://forums.freebsd.org/archive/index.php/t-10270.html) */ -#endif - - return flags; -} - -unsigned int -ev_embeddable_backends (void) -{ - int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT; - - /* epoll embeddability broken on all linux versions up to at least 2.6.23 */ - if (ev_linux_version () < 0x020620) /* disable it on linux < 2.6.32 */ - flags &= ~EVBACKEND_EPOLL; - - return flags; -} - -unsigned int -ev_backend (EV_P) -{ - return backend; -} - -#if EV_FEATURE_API -unsigned int -ev_iteration (EV_P) -{ - return loop_count; -} - -unsigned int -ev_depth (EV_P) -{ - return loop_depth; -} - -void -ev_set_io_collect_interval (EV_P_ ev_tstamp interval) -{ - io_blocktime = interval; -} - -void -ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) -{ - timeout_blocktime = interval; -} - -void -ev_set_userdata (EV_P_ void *data) -{ - userdata = data; -} - -void * -ev_userdata (EV_P) -{ - return userdata; -} - -void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)) -{ - invoke_cb = invoke_pending_cb; -} - -void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)) -{ - release_cb = release; - acquire_cb = acquire; -} -#endif - -/* initialise a loop structure, must be zero-initialised */ -static void noinline -loop_init (EV_P_ unsigned int flags) -{ - if (!backend) - { - origflags = flags; - -#if EV_USE_REALTIME - if (!have_realtime) - { - struct timespec ts; - - if (!clock_gettime (CLOCK_REALTIME, &ts)) - have_realtime = 1; - } -#endif - -#if EV_USE_MONOTONIC - if (!have_monotonic) - { - struct timespec ts; - - if (!clock_gettime (CLOCK_MONOTONIC, &ts)) - have_monotonic = 1; - } -#endif - - /* pid check not overridable via env */ -#ifndef _WIN32 - if (flags & EVFLAG_FORKCHECK) - curpid = getpid (); -#endif - - if (!(flags & EVFLAG_NOENV) - && !enable_secure () - && getenv ("LIBEV_FLAGS")) - flags = atoi (getenv ("LIBEV_FLAGS")); - - ev_rt_now = ev_time (); - mn_now = get_clock (); - now_floor = mn_now; - rtmn_diff = ev_rt_now - mn_now; -#if EV_FEATURE_API - invoke_cb = ev_invoke_pending; -#endif - - io_blocktime = 0.; - timeout_blocktime = 0.; - backend = 0; - backend_fd = -1; - sig_pending = 0; -#if EV_ASYNC_ENABLE - async_pending = 0; -#endif -#if EV_USE_INOTIFY - fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2; -#endif -#if EV_USE_SIGNALFD - sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; -#endif - - if (!(flags & EVBACKEND_MASK)) - flags |= ev_recommended_backends (); - -#if EV_USE_IOCP - if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags); -#endif -#if EV_USE_PORT - if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags); -#endif -#if EV_USE_KQUEUE - if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags); -#endif -#if EV_USE_EPOLL - if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags); -#endif -#if EV_USE_POLL - if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags); -#endif -#if EV_USE_SELECT - if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags); -#endif - - ev_prepare_init (&pending_w, pendingcb); - -#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE - ev_init (&pipe_w, pipecb); - ev_set_priority (&pipe_w, EV_MAXPRI); -#endif - } -} - -/* free up a loop structure */ -void -ev_loop_destroy (EV_P) -{ - int i; - -#if EV_MULTIPLICITY - /* mimic free (0) */ - if (!EV_A) - return; -#endif - -#if EV_CLEANUP_ENABLE - /* queue cleanup watchers (and execute them) */ - if (expect_false (cleanupcnt)) - { - queue_events (EV_A_ (W *)cleanups, cleanupcnt, EV_CLEANUP); - EV_INVOKE_PENDING; - } -#endif - -#if EV_CHILD_ENABLE - if (ev_is_active (&childev)) - { - ev_ref (EV_A); /* child watcher */ - ev_signal_stop (EV_A_ &childev); - } -#endif - - if (ev_is_active (&pipe_w)) - { - /*ev_ref (EV_A);*/ - /*ev_io_stop (EV_A_ &pipe_w);*/ - -#if EV_USE_EVENTFD - if (evfd >= 0) - close (evfd); -#endif - - if (evpipe [0] >= 0) - { - EV_WIN32_CLOSE_FD (evpipe [0]); - EV_WIN32_CLOSE_FD (evpipe [1]); - } - } - -#if EV_USE_SIGNALFD - if (ev_is_active (&sigfd_w)) - close (sigfd); -#endif - -#if EV_USE_INOTIFY - if (fs_fd >= 0) - close (fs_fd); -#endif - - if (backend_fd >= 0) - close (backend_fd); - -#if EV_USE_IOCP - if (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A); -#endif -#if EV_USE_PORT - if (backend == EVBACKEND_PORT ) port_destroy (EV_A); -#endif -#if EV_USE_KQUEUE - if (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A); -#endif -#if EV_USE_EPOLL - if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A); -#endif -#if EV_USE_POLL - if (backend == EVBACKEND_POLL ) poll_destroy (EV_A); -#endif -#if EV_USE_SELECT - if (backend == EVBACKEND_SELECT) select_destroy (EV_A); -#endif - - for (i = NUMPRI; i--; ) - { - array_free (pending, [i]); -#if EV_IDLE_ENABLE - array_free (idle, [i]); -#endif - } - - ev_free (anfds); anfds = 0; anfdmax = 0; - - /* have to use the microsoft-never-gets-it-right macro */ - array_free (rfeed, EMPTY); - array_free (fdchange, EMPTY); - array_free (timer, EMPTY); -#if EV_PERIODIC_ENABLE - array_free (periodic, EMPTY); -#endif -#if EV_FORK_ENABLE - array_free (fork, EMPTY); -#endif -#if EV_CLEANUP_ENABLE - array_free (cleanup, EMPTY); -#endif - array_free (prepare, EMPTY); - array_free (check, EMPTY); -#if EV_ASYNC_ENABLE - array_free (async, EMPTY); -#endif - - backend = 0; - -#if EV_MULTIPLICITY - if (ev_is_default_loop (EV_A)) -#endif - ev_default_loop_ptr = 0; -#if EV_MULTIPLICITY - else - ev_free (EV_A); -#endif -} - -#if EV_USE_INOTIFY -inline_size void infy_fork (EV_P); -#endif - -inline_size void -loop_fork (EV_P) -{ -#if EV_USE_PORT - if (backend == EVBACKEND_PORT ) port_fork (EV_A); -#endif -#if EV_USE_KQUEUE - if (backend == EVBACKEND_KQUEUE) kqueue_fork (EV_A); -#endif -#if EV_USE_EPOLL - if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A); -#endif -#if EV_USE_INOTIFY - infy_fork (EV_A); -#endif - - if (ev_is_active (&pipe_w)) - { - /* this "locks" the handlers against writing to the pipe */ - /* while we modify the fd vars */ - sig_pending = 1; -#if EV_ASYNC_ENABLE - async_pending = 1; -#endif - - ev_ref (EV_A); - ev_io_stop (EV_A_ &pipe_w); - -#if EV_USE_EVENTFD - if (evfd >= 0) - close (evfd); -#endif - - if (evpipe [0] >= 0) - { - EV_WIN32_CLOSE_FD (evpipe [0]); - EV_WIN32_CLOSE_FD (evpipe [1]); - } - -#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE - evpipe_init (EV_A); - /* now iterate over everything, in case we missed something */ - pipecb (EV_A_ &pipe_w, EV_READ); -#endif - } - - postfork = 0; -} - -#if EV_MULTIPLICITY - -struct ev_loop * -ev_loop_new (unsigned int flags) -{ - EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop)); - - memset (EV_A, 0, sizeof (struct ev_loop)); - loop_init (EV_A_ flags); - - if (ev_backend (EV_A)) - return EV_A; - - ev_free (EV_A); - return 0; -} - -#endif /* multiplicity */ - -#if EV_VERIFY -static void noinline -verify_watcher (EV_P_ W w) -{ - assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI)); - - if (w->pending) - assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w)); -} - -static void noinline -verify_heap (EV_P_ ANHE *heap, int N) -{ - int i; - - for (i = HEAP0; i < N + HEAP0; ++i) - { - assert (("libev: active index mismatch in heap", ev_active (ANHE_w (heap [i])) == i)); - assert (("libev: heap condition violated", i == HEAP0 || ANHE_at (heap [HPARENT (i)]) <= ANHE_at (heap [i]))); - assert (("libev: heap at cache mismatch", ANHE_at (heap [i]) == ev_at (ANHE_w (heap [i])))); - - verify_watcher (EV_A_ (W)ANHE_w (heap [i])); - } -} - -static void noinline -array_verify (EV_P_ W *ws, int cnt) -{ - while (cnt--) - { - assert (("libev: active index mismatch", ev_active (ws [cnt]) == cnt + 1)); - verify_watcher (EV_A_ ws [cnt]); - } -} -#endif - -#if EV_FEATURE_API -void -ev_verify (EV_P) -{ -#if EV_VERIFY - int i; - WL w; - - assert (activecnt >= -1); - - assert (fdchangemax >= fdchangecnt); - for (i = 0; i < fdchangecnt; ++i) - assert (("libev: negative fd in fdchanges", fdchanges [i] >= 0)); - - assert (anfdmax >= 0); - for (i = 0; i < anfdmax; ++i) - for (w = anfds [i].head; w; w = w->next) - { - verify_watcher (EV_A_ (W)w); - assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1)); - assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i)); - } - - assert (timermax >= timercnt); - verify_heap (EV_A_ timers, timercnt); - -#if EV_PERIODIC_ENABLE - assert (periodicmax >= periodiccnt); - verify_heap (EV_A_ periodics, periodiccnt); -#endif - - for (i = NUMPRI; i--; ) - { - assert (pendingmax [i] >= pendingcnt [i]); -#if EV_IDLE_ENABLE - assert (idleall >= 0); - assert (idlemax [i] >= idlecnt [i]); - array_verify (EV_A_ (W *)idles [i], idlecnt [i]); -#endif - } - -#if EV_FORK_ENABLE - assert (forkmax >= forkcnt); - array_verify (EV_A_ (W *)forks, forkcnt); -#endif - -#if EV_CLEANUP_ENABLE - assert (cleanupmax >= cleanupcnt); - array_verify (EV_A_ (W *)cleanups, cleanupcnt); -#endif - -#if EV_ASYNC_ENABLE - assert (asyncmax >= asynccnt); - array_verify (EV_A_ (W *)asyncs, asynccnt); -#endif - -#if EV_PREPARE_ENABLE - assert (preparemax >= preparecnt); - array_verify (EV_A_ (W *)prepares, preparecnt); -#endif - -#if EV_CHECK_ENABLE - assert (checkmax >= checkcnt); - array_verify (EV_A_ (W *)checks, checkcnt); -#endif - -# if 0 -#if EV_CHILD_ENABLE - for (w = (ev_child *)childs [chain & ((EV_PID_HASHSIZE) - 1)]; w; w = (ev_child *)((WL)w)->next) - for (signum = EV_NSIG; signum--; ) if (signals [signum].pending) -#endif -# endif -#endif -} -#endif - -#if EV_MULTIPLICITY -struct ev_loop * -#else -int -#endif -ev_default_loop (unsigned int flags) -{ - if (!ev_default_loop_ptr) - { -#if EV_MULTIPLICITY - EV_P = ev_default_loop_ptr = &default_loop_struct; -#else - ev_default_loop_ptr = 1; -#endif - - loop_init (EV_A_ flags); - - if (ev_backend (EV_A)) - { -#if EV_CHILD_ENABLE - ev_signal_init (&childev, childcb, SIGCHLD); - ev_set_priority (&childev, EV_MAXPRI); - ev_signal_start (EV_A_ &childev); - ev_unref (EV_A); /* child watcher should not keep loop alive */ -#endif - } - else - ev_default_loop_ptr = 0; - } - - return ev_default_loop_ptr; -} - -void -ev_loop_fork (EV_P) -{ - postfork = 1; /* must be in line with ev_default_fork */ -} - -/*****************************************************************************/ - -void -ev_invoke (EV_P_ void *w, int revents) -{ - EV_CB_INVOKE ((W)w, revents); -} - -unsigned int -ev_pending_count (EV_P) -{ - int pri; - unsigned int count = 0; - - for (pri = NUMPRI; pri--; ) - count += pendingcnt [pri]; - - return count; -} - -void noinline -ev_invoke_pending (EV_P) -{ - int pri; - - for (pri = NUMPRI; pri--; ) - while (pendingcnt [pri]) - { - ANPENDING *p = pendings [pri] + --pendingcnt [pri]; - - p->w->pending = 0; - EV_CB_INVOKE (p->w, p->events); - EV_FREQUENT_CHECK; - } -} - -#if EV_IDLE_ENABLE -/* make idle watchers pending. this handles the "call-idle */ -/* only when higher priorities are idle" logic */ -inline_size void -idle_reify (EV_P) -{ - if (expect_false (idleall)) - { - int pri; - - for (pri = NUMPRI; pri--; ) - { - if (pendingcnt [pri]) - break; - - if (idlecnt [pri]) - { - queue_events (EV_A_ (W *)idles [pri], idlecnt [pri], EV_IDLE); - break; - } - } - } -} -#endif - -/* make timers pending */ -inline_size void -timers_reify (EV_P) -{ - EV_FREQUENT_CHECK; - - if (timercnt && ANHE_at (timers [HEAP0]) < mn_now) - { - do - { - ev_timer *w = (ev_timer *)ANHE_w (timers [HEAP0]); - - /*assert (("libev: inactive timer on timer heap detected", ev_is_active (w)));*/ - - /* first reschedule or stop timer */ - if (w->repeat) - { - ev_at (w) += w->repeat; - if (ev_at (w) < mn_now) - ev_at (w) = mn_now; - - assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > 0.)); - - ANHE_at_cache (timers [HEAP0]); - downheap (timers, timercnt, HEAP0); - } - else - ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer */ - - EV_FREQUENT_CHECK; - feed_reverse (EV_A_ (W)w); - } - while (timercnt && ANHE_at (timers [HEAP0]) < mn_now); - - feed_reverse_done (EV_A_ EV_TIMER); - } -} - -#if EV_PERIODIC_ENABLE - -inline_speed void -periodic_recalc (EV_P_ ev_periodic *w) -{ - /* TODO: use slow but potentially more correct incremental algo, */ - /* also do not rely on ceil */ - ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval; -} - -/* make periodics pending */ -inline_size void -periodics_reify (EV_P) -{ - EV_FREQUENT_CHECK; - - while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now) - { - int feed_count = 0; - - do - { - ev_periodic *w = (ev_periodic *)ANHE_w (periodics [HEAP0]); - - /*assert (("libev: inactive timer on periodic heap detected", ev_is_active (w)));*/ - - /* first reschedule or stop timer */ - if (w->reschedule_cb) - { - ev_at (w) = w->reschedule_cb (w, ev_rt_now); - - assert (("libev: ev_periodic reschedule callback returned time in the past", ev_at (w) >= ev_rt_now)); - - ANHE_at_cache (periodics [HEAP0]); - downheap (periodics, periodiccnt, HEAP0); - } - else if (w->interval) - { - periodic_recalc (EV_A_ w); - - /* if next trigger time is not sufficiently in the future, put it there */ - /* this might happen because of floating point inexactness */ - if (ev_at (w) - ev_rt_now < TIME_EPSILON) - { - ev_at (w) += w->interval; - - /* if interval is unreasonably low we might still have a time in the past */ - /* so correct this. this will make the periodic very inexact, but the user */ - /* has effectively asked to get triggered more often than possible */ - if (ev_at (w) < ev_rt_now) - ev_at (w) = ev_rt_now; - } - - ANHE_at_cache (periodics [HEAP0]); - downheap (periodics, periodiccnt, HEAP0); - } - else - ev_periodic_stop (EV_A_ w); /* nonrepeating: stop timer */ - - EV_FREQUENT_CHECK; - feed_reverse (EV_A_ (W)w); - } - while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now); - - feed_reverse_done (EV_A_ EV_PERIODIC); - } -} - -/* simply recalculate all periodics */ -/* TODO: maybe ensure that at least one event happens when jumping forward? */ -static void noinline -periodics_reschedule (EV_P) -{ - int i; - - /* adjust periodics after time jump */ - for (i = HEAP0; i < periodiccnt + HEAP0; ++i) - { - ev_periodic *w = (ev_periodic *)ANHE_w (periodics [i]); - - if (w->reschedule_cb) - ev_at (w) = w->reschedule_cb (w, ev_rt_now); - else if (w->interval) - periodic_recalc (EV_A_ w); - - ANHE_at_cache (periodics [i]); - } - - reheap (periodics, periodiccnt); -} -#endif - -/* adjust all timers by a given offset */ -static void noinline -timers_reschedule (EV_P_ ev_tstamp adjust) -{ - int i; - - for (i = 0; i < timercnt; ++i) - { - ANHE *he = timers + i + HEAP0; - ANHE_w (*he)->at += adjust; - ANHE_at_cache (*he); - } -} - -/* fetch new monotonic and realtime times from the kernel */ -/* also detect if there was a timejump, and act accordingly */ -inline_speed void -time_update (EV_P_ ev_tstamp max_block) -{ -#if EV_USE_MONOTONIC - if (expect_true (have_monotonic)) - { - int i; - ev_tstamp odiff = rtmn_diff; - - mn_now = get_clock (); - - /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */ - /* interpolate in the meantime */ - if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5)) - { - ev_rt_now = rtmn_diff + mn_now; - return; - } - - now_floor = mn_now; - ev_rt_now = ev_time (); - - /* loop a few times, before making important decisions. - * on the choice of "4": one iteration isn't enough, - * in case we get preempted during the calls to - * ev_time and get_clock. a second call is almost guaranteed - * to succeed in that case, though. and looping a few more times - * doesn't hurt either as we only do this on time-jumps or - * in the unlikely event of having been preempted here. - */ - for (i = 4; --i; ) - { - rtmn_diff = ev_rt_now - mn_now; - - if (expect_true (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP)) - return; /* all is well */ - - ev_rt_now = ev_time (); - mn_now = get_clock (); - now_floor = mn_now; - } - - /* no timer adjustment, as the monotonic clock doesn't jump */ - /* timers_reschedule (EV_A_ rtmn_diff - odiff) */ -# if EV_PERIODIC_ENABLE - periodics_reschedule (EV_A); -# endif - } - else -#endif - { - ev_rt_now = ev_time (); - - if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP)) - { - /* adjust timers. this is easy, as the offset is the same for all of them */ - timers_reschedule (EV_A_ ev_rt_now - mn_now); -#if EV_PERIODIC_ENABLE - periodics_reschedule (EV_A); -#endif - } - - mn_now = ev_rt_now; - } -} - -void -ev_run (EV_P_ int flags) -{ -#if EV_FEATURE_API - ++loop_depth; -#endif - - assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE)); - - loop_done = EVBREAK_CANCEL; - - EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ - - do - { -#if EV_VERIFY >= 2 - ev_verify (EV_A); -#endif - -#ifndef _WIN32 - if (expect_false (curpid)) /* penalise the forking check even more */ - if (expect_false (getpid () != curpid)) - { - curpid = getpid (); - postfork = 1; - } -#endif - -#if EV_FORK_ENABLE - /* we might have forked, so queue fork handlers */ - if (expect_false (postfork)) - if (forkcnt) - { - queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK); - EV_INVOKE_PENDING; - } -#endif - -#if EV_PREPARE_ENABLE - /* queue prepare watchers (and execute them) */ - if (expect_false (preparecnt)) - { - queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE); - EV_INVOKE_PENDING; - } -#endif - - if (expect_false (loop_done)) - break; - - /* we might have forked, so reify kernel state if necessary */ - if (expect_false (postfork)) - loop_fork (EV_A); - - /* update fd-related kernel structures */ - fd_reify (EV_A); - - /* calculate blocking time */ - { - ev_tstamp waittime = 0.; - ev_tstamp sleeptime = 0.; - - /* remember old timestamp for io_blocktime calculation */ - ev_tstamp prev_mn_now = mn_now; - - /* update time to cancel out callback processing overhead */ - time_update (EV_A_ 1e100); - - if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt))) - { - waittime = MAX_BLOCKTIME; - - if (timercnt) - { - ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge; - if (waittime > to) waittime = to; - } - -#if EV_PERIODIC_ENABLE - if (periodiccnt) - { - ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge; - if (waittime > to) waittime = to; - } -#endif - - /* don't let timeouts decrease the waittime below timeout_blocktime */ - if (expect_false (waittime < timeout_blocktime)) - waittime = timeout_blocktime; - - /* extra check because io_blocktime is commonly 0 */ - if (expect_false (io_blocktime)) - { - sleeptime = io_blocktime - (mn_now - prev_mn_now); - - if (sleeptime > waittime - backend_fudge) - sleeptime = waittime - backend_fudge; - - if (expect_true (sleeptime > 0.)) - { - ev_sleep (sleeptime); - waittime -= sleeptime; - } - } - } - -#if EV_FEATURE_API - ++loop_count; -#endif - assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ - backend_poll (EV_A_ waittime); - assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ - - /* update ev_rt_now, do magic */ - time_update (EV_A_ waittime + sleeptime); - } - - /* queue pending timers and reschedule them */ - timers_reify (EV_A); /* relative timers called last */ -#if EV_PERIODIC_ENABLE - periodics_reify (EV_A); /* absolute timers called first */ -#endif - -#if EV_IDLE_ENABLE - /* queue idle watchers unless other events are pending */ - idle_reify (EV_A); -#endif - -#if EV_CHECK_ENABLE - /* queue check watchers, to be executed first */ - if (expect_false (checkcnt)) - queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK); -#endif - - EV_INVOKE_PENDING; - } - while (expect_true ( - activecnt - && !loop_done - && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT)) - )); - - if (loop_done == EVBREAK_ONE) - loop_done = EVBREAK_CANCEL; - -#if EV_FEATURE_API - --loop_depth; -#endif -} - -void -ev_break (EV_P_ int how) -{ - loop_done = how; -} - -void -ev_ref (EV_P) -{ - ++activecnt; -} - -void -ev_unref (EV_P) -{ - --activecnt; -} - -void -ev_now_update (EV_P) -{ - time_update (EV_A_ 1e100); -} - -void -ev_suspend (EV_P) -{ - ev_now_update (EV_A); -} - -void -ev_resume (EV_P) -{ - ev_tstamp mn_prev = mn_now; - - ev_now_update (EV_A); - timers_reschedule (EV_A_ mn_now - mn_prev); -#if EV_PERIODIC_ENABLE - /* TODO: really do this? */ - periodics_reschedule (EV_A); -#endif -} - -/*****************************************************************************/ -/* singly-linked list management, used when the expected list length is short */ - -inline_size void -wlist_add (WL *head, WL elem) -{ - elem->next = *head; - *head = elem; -} - -inline_size void -wlist_del (WL *head, WL elem) -{ - while (*head) - { - if (expect_true (*head == elem)) - { - *head = elem->next; - break; - } - - head = &(*head)->next; - } -} - -/* internal, faster, version of ev_clear_pending */ -inline_speed void -clear_pending (EV_P_ W w) -{ - if (w->pending) - { - pendings [ABSPRI (w)][w->pending - 1].w = (W)&pending_w; - w->pending = 0; - } -} - -int -ev_clear_pending (EV_P_ void *w) -{ - W w_ = (W)w; - int pending = w_->pending; - - if (expect_true (pending)) - { - ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1; - p->w = (W)&pending_w; - w_->pending = 0; - return p->events; - } - else - return 0; -} - -inline_size void -pri_adjust (EV_P_ W w) -{ - int pri = ev_priority (w); - pri = pri < EV_MINPRI ? EV_MINPRI : pri; - pri = pri > EV_MAXPRI ? EV_MAXPRI : pri; - ev_set_priority (w, pri); -} - -inline_speed void -ev_start (EV_P_ W w, int active) -{ - pri_adjust (EV_A_ w); - w->active = active; - ev_ref (EV_A); -} - -inline_size void -ev_stop (EV_P_ W w) -{ - ev_unref (EV_A); - w->active = 0; -} - -/*****************************************************************************/ - -void noinline -ev_io_start (EV_P_ ev_io *w) -{ - int fd = w->fd; - - if (expect_false (ev_is_active (w))) - return; - - assert (("libev: ev_io_start called with negative fd", fd >= 0)); - assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE)))); - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, 1); - array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero); - wlist_add (&anfds[fd].head, (WL)w); - - fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY); - w->events &= ~EV__IOFDSET; - - EV_FREQUENT_CHECK; -} - -void noinline -ev_io_stop (EV_P_ ev_io *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - assert (("libev: ev_io_stop called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax)); - - EV_FREQUENT_CHECK; - - wlist_del (&anfds[w->fd].head, (WL)w); - ev_stop (EV_A_ (W)w); - - fd_change (EV_A_ w->fd, EV_ANFD_REIFY); - - EV_FREQUENT_CHECK; -} - -void noinline -ev_timer_start (EV_P_ ev_timer *w) -{ - if (expect_false (ev_is_active (w))) - return; - - ev_at (w) += mn_now; - - assert (("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.)); - - EV_FREQUENT_CHECK; - - ++timercnt; - ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1); - array_needsize (ANHE, timers, timermax, ev_active (w) + 1, EMPTY2); - ANHE_w (timers [ev_active (w)]) = (WT)w; - ANHE_at_cache (timers [ev_active (w)]); - upheap (timers, ev_active (w)); - - EV_FREQUENT_CHECK; - - /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/ -} - -void noinline -ev_timer_stop (EV_P_ ev_timer *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - assert (("libev: internal timer heap corruption", ANHE_w (timers [active]) == (WT)w)); - - --timercnt; - - if (expect_true (active < timercnt + HEAP0)) - { - timers [active] = timers [timercnt + HEAP0]; - adjustheap (timers, timercnt, active); - } - } - - ev_at (w) -= mn_now; - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} - -void noinline -ev_timer_again (EV_P_ ev_timer *w) -{ - EV_FREQUENT_CHECK; - - if (ev_is_active (w)) - { - if (w->repeat) - { - ev_at (w) = mn_now + w->repeat; - ANHE_at_cache (timers [ev_active (w)]); - adjustheap (timers, timercnt, ev_active (w)); - } - else - ev_timer_stop (EV_A_ w); - } - else if (w->repeat) - { - ev_at (w) = w->repeat; - ev_timer_start (EV_A_ w); - } - - EV_FREQUENT_CHECK; -} - -ev_tstamp -ev_timer_remaining (EV_P_ ev_timer *w) -{ - return ev_at (w) - (ev_is_active (w) ? mn_now : 0.); -} - -#if EV_PERIODIC_ENABLE -void noinline -ev_periodic_start (EV_P_ ev_periodic *w) -{ - if (expect_false (ev_is_active (w))) - return; - - if (w->reschedule_cb) - ev_at (w) = w->reschedule_cb (w, ev_rt_now); - else if (w->interval) - { - assert (("libev: ev_periodic_start called with negative interval value", w->interval >= 0.)); - periodic_recalc (EV_A_ w); - } - else - ev_at (w) = w->offset; - - EV_FREQUENT_CHECK; - - ++periodiccnt; - ev_start (EV_A_ (W)w, periodiccnt + HEAP0 - 1); - array_needsize (ANHE, periodics, periodicmax, ev_active (w) + 1, EMPTY2); - ANHE_w (periodics [ev_active (w)]) = (WT)w; - ANHE_at_cache (periodics [ev_active (w)]); - upheap (periodics, ev_active (w)); - - EV_FREQUENT_CHECK; - - /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/ -} - -void noinline -ev_periodic_stop (EV_P_ ev_periodic *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - assert (("libev: internal periodic heap corruption", ANHE_w (periodics [active]) == (WT)w)); - - --periodiccnt; - - if (expect_true (active < periodiccnt + HEAP0)) - { - periodics [active] = periodics [periodiccnt + HEAP0]; - adjustheap (periodics, periodiccnt, active); - } - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} - -void noinline -ev_periodic_again (EV_P_ ev_periodic *w) -{ - /* TODO: use adjustheap and recalculation */ - ev_periodic_stop (EV_A_ w); - ev_periodic_start (EV_A_ w); -} -#endif - -#ifndef SA_RESTART -# define SA_RESTART 0 -#endif - -#if EV_SIGNAL_ENABLE - -void noinline -ev_signal_start (EV_P_ ev_signal *w) -{ - if (expect_false (ev_is_active (w))) - return; - - assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG)); - -#if EV_MULTIPLICITY - assert (("libev: a signal must not be attached to two different loops", - !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop)); - - signals [w->signum - 1].loop = EV_A; -#endif - - EV_FREQUENT_CHECK; - -#if EV_USE_SIGNALFD - if (sigfd == -2) - { - sigfd = signalfd (-1, &sigfd_set, SFD_NONBLOCK | SFD_CLOEXEC); - if (sigfd < 0 && errno == EINVAL) - sigfd = signalfd (-1, &sigfd_set, 0); /* retry without flags */ - - if (sigfd >= 0) - { - fd_intern (sigfd); /* doing it twice will not hurt */ - - sigemptyset (&sigfd_set); - - ev_io_init (&sigfd_w, sigfdcb, sigfd, EV_READ); - ev_set_priority (&sigfd_w, EV_MAXPRI); - ev_io_start (EV_A_ &sigfd_w); - ev_unref (EV_A); /* signalfd watcher should not keep loop alive */ - } - } - - if (sigfd >= 0) - { - /* TODO: check .head */ - sigaddset (&sigfd_set, w->signum); - sigprocmask (SIG_BLOCK, &sigfd_set, 0); - - signalfd (sigfd, &sigfd_set, 0); - } -#endif - - ev_start (EV_A_ (W)w, 1); - wlist_add (&signals [w->signum - 1].head, (WL)w); - - if (!((WL)w)->next) -# if EV_USE_SIGNALFD - if (sigfd < 0) /*TODO*/ -# endif - { -# ifdef _WIN32 - evpipe_init (EV_A); - - signal (w->signum, ev_sighandler); -# else - struct sigaction sa; - - evpipe_init (EV_A); - - sa.sa_handler = ev_sighandler; - sigfillset (&sa.sa_mask); - sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */ - sigaction (w->signum, &sa, 0); - - if (origflags & EVFLAG_NOSIGMASK) - { - sigemptyset (&sa.sa_mask); - sigaddset (&sa.sa_mask, w->signum); - sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); - } -#endif - } - - EV_FREQUENT_CHECK; -} - -void noinline -ev_signal_stop (EV_P_ ev_signal *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - wlist_del (&signals [w->signum - 1].head, (WL)w); - ev_stop (EV_A_ (W)w); - - if (!signals [w->signum - 1].head) - { -#if EV_MULTIPLICITY - signals [w->signum - 1].loop = 0; /* unattach from signal */ -#endif -#if EV_USE_SIGNALFD - if (sigfd >= 0) - { - sigset_t ss; - - sigemptyset (&ss); - sigaddset (&ss, w->signum); - sigdelset (&sigfd_set, w->signum); - - signalfd (sigfd, &sigfd_set, 0); - sigprocmask (SIG_UNBLOCK, &ss, 0); - } - else -#endif - signal (w->signum, SIG_DFL); - } - - EV_FREQUENT_CHECK; -} - -#endif - -#if EV_CHILD_ENABLE - -void -ev_child_start (EV_P_ ev_child *w) -{ -#if EV_MULTIPLICITY - assert (("libev: child watchers are only supported in the default loop", loop == ev_default_loop_ptr)); -#endif - if (expect_false (ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, 1); - wlist_add (&childs [w->pid & ((EV_PID_HASHSIZE) - 1)], (WL)w); - - EV_FREQUENT_CHECK; -} - -void -ev_child_stop (EV_P_ ev_child *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - wlist_del (&childs [w->pid & ((EV_PID_HASHSIZE) - 1)], (WL)w); - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} - -#endif - -#if EV_STAT_ENABLE - -# ifdef _WIN32 -# undef lstat -# define lstat(a,b) _stati64 (a,b) -# endif - -#define DEF_STAT_INTERVAL 5.0074891 -#define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */ -#define MIN_STAT_INTERVAL 0.1074891 - -static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents); - -#if EV_USE_INOTIFY - -/* the * 2 is to allow for alignment padding, which for some reason is >> 8 */ -# define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX) - -static void noinline -infy_add (EV_P_ ev_stat *w) -{ - w->wd = inotify_add_watch (fs_fd, w->path, IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY | IN_DONT_FOLLOW | IN_MASK_ADD); - - if (w->wd >= 0) - { - struct statfs sfs; - - /* now local changes will be tracked by inotify, but remote changes won't */ - /* unless the filesystem is known to be local, we therefore still poll */ - /* also do poll on <2.6.25, but with normal frequency */ - - if (!fs_2625) - w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; - else if (!statfs (w->path, &sfs) - && (sfs.f_type == 0x1373 /* devfs */ - || sfs.f_type == 0xEF53 /* ext2/3 */ - || sfs.f_type == 0x3153464a /* jfs */ - || sfs.f_type == 0x52654973 /* reiser3 */ - || sfs.f_type == 0x01021994 /* tempfs */ - || sfs.f_type == 0x58465342 /* xfs */)) - w->timer.repeat = 0.; /* filesystem is local, kernel new enough */ - else - w->timer.repeat = w->interval ? w->interval : NFS_STAT_INTERVAL; /* remote, use reduced frequency */ - } - else - { - /* can't use inotify, continue to stat */ - w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; - - /* if path is not there, monitor some parent directory for speedup hints */ - /* note that exceeding the hardcoded path limit is not a correctness issue, */ - /* but an efficiency issue only */ - if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096) - { - char path [4096]; - strcpy (path, w->path); - - do - { - int mask = IN_MASK_ADD | IN_DELETE_SELF | IN_MOVE_SELF - | (errno == EACCES ? IN_ATTRIB : IN_CREATE | IN_MOVED_TO); - - char *pend = strrchr (path, '/'); - - if (!pend || pend == path) - break; - - *pend = 0; - w->wd = inotify_add_watch (fs_fd, path, mask); - } - while (w->wd < 0 && (errno == ENOENT || errno == EACCES)); - } - } - - if (w->wd >= 0) - wlist_add (&fs_hash [w->wd & ((EV_INOTIFY_HASHSIZE) - 1)].head, (WL)w); - - /* now re-arm timer, if required */ - if (ev_is_active (&w->timer)) ev_ref (EV_A); - ev_timer_again (EV_A_ &w->timer); - if (ev_is_active (&w->timer)) ev_unref (EV_A); -} - -static void noinline -infy_del (EV_P_ ev_stat *w) -{ - int slot; - int wd = w->wd; - - if (wd < 0) - return; - - w->wd = -2; - slot = wd & ((EV_INOTIFY_HASHSIZE) - 1); - wlist_del (&fs_hash [slot].head, (WL)w); - - /* remove this watcher, if others are watching it, they will rearm */ - inotify_rm_watch (fs_fd, wd); -} - -static void noinline -infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev) -{ - if (slot < 0) - /* overflow, need to check for all hash slots */ - for (slot = 0; slot < (EV_INOTIFY_HASHSIZE); ++slot) - infy_wd (EV_A_ slot, wd, ev); - else - { - WL w_; - - for (w_ = fs_hash [slot & ((EV_INOTIFY_HASHSIZE) - 1)].head; w_; ) - { - ev_stat *w = (ev_stat *)w_; - w_ = w_->next; /* lets us remove this watcher and all before it */ - - if (w->wd == wd || wd == -1) - { - if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF)) - { - wlist_del (&fs_hash [slot & ((EV_INOTIFY_HASHSIZE) - 1)].head, (WL)w); - w->wd = -1; - infy_add (EV_A_ w); /* re-add, no matter what */ - } - - stat_timer_cb (EV_A_ &w->timer, 0); - } - } - } -} - -static void -infy_cb (EV_P_ ev_io *w, int revents) -{ - char buf [EV_INOTIFY_BUFSIZE]; - int ofs; - int len = read (fs_fd, buf, sizeof (buf)); - - for (ofs = 0; ofs < len; ) - { - struct inotify_event *ev = (struct inotify_event *)(buf + ofs); - infy_wd (EV_A_ ev->wd, ev->wd, ev); - ofs += sizeof (struct inotify_event) + ev->len; - } -} - -inline_size void -ev_check_2625 (EV_P) -{ - /* kernels < 2.6.25 are borked - * http://www.ussg.indiana.edu/hypermail/linux/kernel/0711.3/1208.html - */ - if (ev_linux_version () < 0x020619) - return; - - fs_2625 = 1; -} - -inline_size int -infy_newfd (void) -{ -#if defined (IN_CLOEXEC) && defined (IN_NONBLOCK) - int fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK); - if (fd >= 0) - return fd; -#endif - return inotify_init (); -} - -inline_size void -infy_init (EV_P) -{ - if (fs_fd != -2) - return; - - fs_fd = -1; - - ev_check_2625 (EV_A); - - fs_fd = infy_newfd (); - - if (fs_fd >= 0) - { - fd_intern (fs_fd); - ev_io_init (&fs_w, infy_cb, fs_fd, EV_READ); - ev_set_priority (&fs_w, EV_MAXPRI); - ev_io_start (EV_A_ &fs_w); - ev_unref (EV_A); - } -} - -inline_size void -infy_fork (EV_P) -{ - int slot; - - if (fs_fd < 0) - return; - - ev_ref (EV_A); - ev_io_stop (EV_A_ &fs_w); - close (fs_fd); - fs_fd = infy_newfd (); - - if (fs_fd >= 0) - { - fd_intern (fs_fd); - ev_io_set (&fs_w, fs_fd, EV_READ); - ev_io_start (EV_A_ &fs_w); - ev_unref (EV_A); - } - - for (slot = 0; slot < (EV_INOTIFY_HASHSIZE); ++slot) - { - WL w_ = fs_hash [slot].head; - fs_hash [slot].head = 0; - - while (w_) - { - ev_stat *w = (ev_stat *)w_; - w_ = w_->next; /* lets us add this watcher */ - - w->wd = -1; - - if (fs_fd >= 0) - infy_add (EV_A_ w); /* re-add, no matter what */ - else - { - w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; - if (ev_is_active (&w->timer)) ev_ref (EV_A); - ev_timer_again (EV_A_ &w->timer); - if (ev_is_active (&w->timer)) ev_unref (EV_A); - } - } - } -} - -#endif - -#ifdef _WIN32 -# define EV_LSTAT(p,b) _stati64 (p, b) -#else -# define EV_LSTAT(p,b) lstat (p, b) -#endif - -void -ev_stat_stat (EV_P_ ev_stat *w) -{ - if (lstat (w->path, &w->attr) < 0) - w->attr.st_nlink = 0; - else if (!w->attr.st_nlink) - w->attr.st_nlink = 1; -} - -static void noinline -stat_timer_cb (EV_P_ ev_timer *w_, int revents) -{ - ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer)); - - ev_statdata prev = w->attr; - ev_stat_stat (EV_A_ w); - - /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */ - if ( - prev.st_dev != w->attr.st_dev - || prev.st_ino != w->attr.st_ino - || prev.st_mode != w->attr.st_mode - || prev.st_nlink != w->attr.st_nlink - || prev.st_uid != w->attr.st_uid - || prev.st_gid != w->attr.st_gid - || prev.st_rdev != w->attr.st_rdev - || prev.st_size != w->attr.st_size - || prev.st_atime != w->attr.st_atime - || prev.st_mtime != w->attr.st_mtime - || prev.st_ctime != w->attr.st_ctime - ) { - /* we only update w->prev on actual differences */ - /* in case we test more often than invoke the callback, */ - /* to ensure that prev is always different to attr */ - w->prev = prev; - - #if EV_USE_INOTIFY - if (fs_fd >= 0) - { - infy_del (EV_A_ w); - infy_add (EV_A_ w); - ev_stat_stat (EV_A_ w); /* avoid race... */ - } - #endif - - ev_feed_event (EV_A_ w, EV_STAT); - } -} - -void -ev_stat_start (EV_P_ ev_stat *w) -{ - if (expect_false (ev_is_active (w))) - return; - - ev_stat_stat (EV_A_ w); - - if (w->interval < MIN_STAT_INTERVAL && w->interval) - w->interval = MIN_STAT_INTERVAL; - - ev_timer_init (&w->timer, stat_timer_cb, 0., w->interval ? w->interval : DEF_STAT_INTERVAL); - ev_set_priority (&w->timer, ev_priority (w)); - -#if EV_USE_INOTIFY - infy_init (EV_A); - - if (fs_fd >= 0) - infy_add (EV_A_ w); - else -#endif - { - ev_timer_again (EV_A_ &w->timer); - ev_unref (EV_A); - } - - ev_start (EV_A_ (W)w, 1); - - EV_FREQUENT_CHECK; -} - -void -ev_stat_stop (EV_P_ ev_stat *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - -#if EV_USE_INOTIFY - infy_del (EV_A_ w); -#endif - - if (ev_is_active (&w->timer)) - { - ev_ref (EV_A); - ev_timer_stop (EV_A_ &w->timer); - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_IDLE_ENABLE -void -ev_idle_start (EV_P_ ev_idle *w) -{ - if (expect_false (ev_is_active (w))) - return; - - pri_adjust (EV_A_ (W)w); - - EV_FREQUENT_CHECK; - - { - int active = ++idlecnt [ABSPRI (w)]; - - ++idleall; - ev_start (EV_A_ (W)w, active); - - array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2); - idles [ABSPRI (w)][active - 1] = w; - } - - EV_FREQUENT_CHECK; -} - -void -ev_idle_stop (EV_P_ ev_idle *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - idles [ABSPRI (w)][active - 1] = idles [ABSPRI (w)][--idlecnt [ABSPRI (w)]]; - ev_active (idles [ABSPRI (w)][active - 1]) = active; - - ev_stop (EV_A_ (W)w); - --idleall; - } - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_PREPARE_ENABLE -void -ev_prepare_start (EV_P_ ev_prepare *w) -{ - if (expect_false (ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, ++preparecnt); - array_needsize (ev_prepare *, prepares, preparemax, preparecnt, EMPTY2); - prepares [preparecnt - 1] = w; - - EV_FREQUENT_CHECK; -} - -void -ev_prepare_stop (EV_P_ ev_prepare *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - prepares [active - 1] = prepares [--preparecnt]; - ev_active (prepares [active - 1]) = active; - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_CHECK_ENABLE -void -ev_check_start (EV_P_ ev_check *w) -{ - if (expect_false (ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, ++checkcnt); - array_needsize (ev_check *, checks, checkmax, checkcnt, EMPTY2); - checks [checkcnt - 1] = w; - - EV_FREQUENT_CHECK; -} - -void -ev_check_stop (EV_P_ ev_check *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - checks [active - 1] = checks [--checkcnt]; - ev_active (checks [active - 1]) = active; - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_EMBED_ENABLE -void noinline -ev_embed_sweep (EV_P_ ev_embed *w) -{ - ev_run (w->other, EVRUN_NOWAIT); -} - -static void -embed_io_cb (EV_P_ ev_io *io, int revents) -{ - ev_embed *w = (ev_embed *)(((char *)io) - offsetof (ev_embed, io)); - - if (ev_cb (w)) - ev_feed_event (EV_A_ (W)w, EV_EMBED); - else - ev_run (w->other, EVRUN_NOWAIT); -} - -static void -embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents) -{ - ev_embed *w = (ev_embed *)(((char *)prepare) - offsetof (ev_embed, prepare)); - - { - EV_P = w->other; - - while (fdchangecnt) - { - fd_reify (EV_A); - ev_run (EV_A_ EVRUN_NOWAIT); - } - } -} - -static void -embed_fork_cb (EV_P_ ev_fork *fork_w, int revents) -{ - ev_embed *w = (ev_embed *)(((char *)fork_w) - offsetof (ev_embed, fork)); - - ev_embed_stop (EV_A_ w); - - { - EV_P = w->other; - - ev_loop_fork (EV_A); - ev_run (EV_A_ EVRUN_NOWAIT); - } - - ev_embed_start (EV_A_ w); -} - -#if 0 -static void -embed_idle_cb (EV_P_ ev_idle *idle, int revents) -{ - ev_idle_stop (EV_A_ idle); -} -#endif - -void -ev_embed_start (EV_P_ ev_embed *w) -{ - if (expect_false (ev_is_active (w))) - return; - - { - EV_P = w->other; - assert (("libev: loop to be embedded is not embeddable", backend & ev_embeddable_backends ())); - ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ); - } - - EV_FREQUENT_CHECK; - - ev_set_priority (&w->io, ev_priority (w)); - ev_io_start (EV_A_ &w->io); - - ev_prepare_init (&w->prepare, embed_prepare_cb); - ev_set_priority (&w->prepare, EV_MINPRI); - ev_prepare_start (EV_A_ &w->prepare); - - ev_fork_init (&w->fork, embed_fork_cb); - ev_fork_start (EV_A_ &w->fork); - - /*ev_idle_init (&w->idle, e,bed_idle_cb);*/ - - ev_start (EV_A_ (W)w, 1); - - EV_FREQUENT_CHECK; -} - -void -ev_embed_stop (EV_P_ ev_embed *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_io_stop (EV_A_ &w->io); - ev_prepare_stop (EV_A_ &w->prepare); - ev_fork_stop (EV_A_ &w->fork); - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_FORK_ENABLE -void -ev_fork_start (EV_P_ ev_fork *w) -{ - if (expect_false (ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, ++forkcnt); - array_needsize (ev_fork *, forks, forkmax, forkcnt, EMPTY2); - forks [forkcnt - 1] = w; - - EV_FREQUENT_CHECK; -} - -void -ev_fork_stop (EV_P_ ev_fork *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - forks [active - 1] = forks [--forkcnt]; - ev_active (forks [active - 1]) = active; - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_CLEANUP_ENABLE -void -ev_cleanup_start (EV_P_ ev_cleanup *w) -{ - if (expect_false (ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, ++cleanupcnt); - array_needsize (ev_cleanup *, cleanups, cleanupmax, cleanupcnt, EMPTY2); - cleanups [cleanupcnt - 1] = w; - - /* cleanup watchers should never keep a refcount on the loop */ - ev_unref (EV_A); - EV_FREQUENT_CHECK; -} - -void -ev_cleanup_stop (EV_P_ ev_cleanup *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - ev_ref (EV_A); - - { - int active = ev_active (w); - - cleanups [active - 1] = cleanups [--cleanupcnt]; - ev_active (cleanups [active - 1]) = active; - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} -#endif - -#if EV_ASYNC_ENABLE -void -ev_async_start (EV_P_ ev_async *w) -{ - if (expect_false (ev_is_active (w))) - return; - - w->sent = 0; - - evpipe_init (EV_A); - - EV_FREQUENT_CHECK; - - ev_start (EV_A_ (W)w, ++asynccnt); - array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2); - asyncs [asynccnt - 1] = w; - - EV_FREQUENT_CHECK; -} - -void -ev_async_stop (EV_P_ ev_async *w) -{ - clear_pending (EV_A_ (W)w); - if (expect_false (!ev_is_active (w))) - return; - - EV_FREQUENT_CHECK; - - { - int active = ev_active (w); - - asyncs [active - 1] = asyncs [--asynccnt]; - ev_active (asyncs [active - 1]) = active; - } - - ev_stop (EV_A_ (W)w); - - EV_FREQUENT_CHECK; -} - -void -ev_async_send (EV_P_ ev_async *w) -{ - w->sent = 1; - evpipe_write (EV_A_ &async_pending); -} -#endif - -/*****************************************************************************/ - -struct ev_once -{ - ev_io io; - ev_timer to; - void (*cb)(int revents, void *arg); - void *arg; -}; - -static void -once_cb (EV_P_ struct ev_once *once, int revents) -{ - void (*cb)(int revents, void *arg) = once->cb; - void *arg = once->arg; - - ev_io_stop (EV_A_ &once->io); - ev_timer_stop (EV_A_ &once->to); - ev_free (once); - - cb (revents, arg); -} - -static void -once_cb_io (EV_P_ ev_io *w, int revents) -{ - struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, io)); - - once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->to)); -} - -static void -once_cb_to (EV_P_ ev_timer *w, int revents) -{ - struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, to)); - - once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->io)); -} - -void -ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) -{ - struct ev_once *once = (struct ev_once *)ev_malloc (sizeof (struct ev_once)); - - if (expect_false (!once)) - { - cb (EV_ERROR | EV_READ | EV_WRITE | EV_TIMER, arg); - return; - } - - once->cb = cb; - once->arg = arg; - - ev_init (&once->io, once_cb_io); - if (fd >= 0) - { - ev_io_set (&once->io, fd, events); - ev_io_start (EV_A_ &once->io); - } - - ev_init (&once->to, once_cb_to); - if (timeout >= 0.) - { - ev_timer_set (&once->to, timeout, 0.); - ev_timer_start (EV_A_ &once->to); - } -} - -/*****************************************************************************/ - -#if EV_WALK_ENABLE -void -ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) -{ - int i, j; - ev_watcher_list *wl, *wn; - - if (types & (EV_IO | EV_EMBED)) - for (i = 0; i < anfdmax; ++i) - for (wl = anfds [i].head; wl; ) - { - wn = wl->next; - -#if EV_EMBED_ENABLE - if (ev_cb ((ev_io *)wl) == embed_io_cb) - { - if (types & EV_EMBED) - cb (EV_A_ EV_EMBED, ((char *)wl) - offsetof (struct ev_embed, io)); - } - else -#endif -#if EV_USE_INOTIFY - if (ev_cb ((ev_io *)wl) == infy_cb) - ; - else -#endif - if ((ev_io *)wl != &pipe_w) - if (types & EV_IO) - cb (EV_A_ EV_IO, wl); - - wl = wn; - } - - if (types & (EV_TIMER | EV_STAT)) - for (i = timercnt + HEAP0; i-- > HEAP0; ) -#if EV_STAT_ENABLE - /*TODO: timer is not always active*/ - if (ev_cb ((ev_timer *)ANHE_w (timers [i])) == stat_timer_cb) - { - if (types & EV_STAT) - cb (EV_A_ EV_STAT, ((char *)ANHE_w (timers [i])) - offsetof (struct ev_stat, timer)); - } - else -#endif - if (types & EV_TIMER) - cb (EV_A_ EV_TIMER, ANHE_w (timers [i])); - -#if EV_PERIODIC_ENABLE - if (types & EV_PERIODIC) - for (i = periodiccnt + HEAP0; i-- > HEAP0; ) - cb (EV_A_ EV_PERIODIC, ANHE_w (periodics [i])); -#endif - -#if EV_IDLE_ENABLE - if (types & EV_IDLE) - for (j = NUMPRI; i--; ) - for (i = idlecnt [j]; i--; ) - cb (EV_A_ EV_IDLE, idles [j][i]); -#endif - -#if EV_FORK_ENABLE - if (types & EV_FORK) - for (i = forkcnt; i--; ) - if (ev_cb (forks [i]) != embed_fork_cb) - cb (EV_A_ EV_FORK, forks [i]); -#endif - -#if EV_ASYNC_ENABLE - if (types & EV_ASYNC) - for (i = asynccnt; i--; ) - cb (EV_A_ EV_ASYNC, asyncs [i]); -#endif - -#if EV_PREPARE_ENABLE - if (types & EV_PREPARE) - for (i = preparecnt; i--; ) -# if EV_EMBED_ENABLE - if (ev_cb (prepares [i]) != embed_prepare_cb) -# endif - cb (EV_A_ EV_PREPARE, prepares [i]); -#endif - -#if EV_CHECK_ENABLE - if (types & EV_CHECK) - for (i = checkcnt; i--; ) - cb (EV_A_ EV_CHECK, checks [i]); -#endif - -#if EV_SIGNAL_ENABLE - if (types & EV_SIGNAL) - for (i = 0; i < EV_NSIG - 1; ++i) - for (wl = signals [i].head; wl; ) - { - wn = wl->next; - cb (EV_A_ EV_SIGNAL, wl); - wl = wn; - } -#endif - -#if EV_CHILD_ENABLE - if (types & EV_CHILD) - for (i = (EV_PID_HASHSIZE); i--; ) - for (wl = childs [i]; wl; ) - { - wn = wl->next; - cb (EV_A_ EV_CHILD, wl); - wl = wn; - } -#endif -/* EV_STAT 0x00001000 /* stat data changed */ -/* EV_EMBED 0x00010000 /* embedded event loop needs sweep */ -} -#endif - -#if EV_MULTIPLICITY - #include "ev_wrap.h" -#endif - -EV_CPP(}) - diff --git a/src/util/k5ev/ev.h b/src/util/k5ev/ev.h deleted file mode 100644 index 27c1778f1f..0000000000 --- a/src/util/k5ev/ev.h +++ /dev/null @@ -1,829 +0,0 @@ -/* - * libev native API header - * - * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -#ifndef EV_H_ -#define EV_H_ - -#ifdef __cplusplus -# define EV_CPP(x) x -#else -# define EV_CPP(x) -#endif - -EV_CPP(extern "C" {) - -/*****************************************************************************/ - -/* pre-4.0 compatibility */ -#ifndef EV_COMPAT3 -# define EV_COMPAT3 1 -#endif - -#ifndef EV_FEATURES -# define EV_FEATURES 0x7f -#endif - -#define EV_FEATURE_CODE ((EV_FEATURES) & 1) -#define EV_FEATURE_DATA ((EV_FEATURES) & 2) -#define EV_FEATURE_CONFIG ((EV_FEATURES) & 4) -#define EV_FEATURE_API ((EV_FEATURES) & 8) -#define EV_FEATURE_WATCHERS ((EV_FEATURES) & 16) -#define EV_FEATURE_BACKENDS ((EV_FEATURES) & 32) -#define EV_FEATURE_OS ((EV_FEATURES) & 64) - -/* these priorities are inclusive, higher priorities will be invoked earlier */ -#ifndef EV_MINPRI -# define EV_MINPRI (EV_FEATURE_CONFIG ? -2 : 0) -#endif -#ifndef EV_MAXPRI -# define EV_MAXPRI (EV_FEATURE_CONFIG ? +2 : 0) -#endif - -#ifndef EV_MULTIPLICITY -# define EV_MULTIPLICITY EV_FEATURE_CONFIG -#endif - -#ifndef EV_PERIODIC_ENABLE -# define EV_PERIODIC_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_STAT_ENABLE -# define EV_STAT_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_PREPARE_ENABLE -# define EV_PREPARE_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_CHECK_ENABLE -# define EV_CHECK_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_IDLE_ENABLE -# define EV_IDLE_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_FORK_ENABLE -# define EV_FORK_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_CLEANUP_ENABLE -# define EV_CLEANUP_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_SIGNAL_ENABLE -# define EV_SIGNAL_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_CHILD_ENABLE -# ifdef _WIN32 -# define EV_CHILD_ENABLE 0 -# else -# define EV_CHILD_ENABLE EV_FEATURE_WATCHERS -#endif -#endif - -#ifndef EV_ASYNC_ENABLE -# define EV_ASYNC_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_EMBED_ENABLE -# define EV_EMBED_ENABLE EV_FEATURE_WATCHERS -#endif - -#ifndef EV_WALK_ENABLE -# define EV_WALK_ENABLE 0 /* not yet */ -#endif - -/*****************************************************************************/ - -#if EV_CHILD_ENABLE && !EV_SIGNAL_ENABLE -# undef EV_SIGNAL_ENABLE -# define EV_SIGNAL_ENABLE 1 -#endif - -/*****************************************************************************/ - -typedef double ev_tstamp; - -#ifndef EV_ATOMIC_T -# include -# define EV_ATOMIC_T sig_atomic_t volatile -#endif - -#if EV_STAT_ENABLE -# ifdef _WIN32 -# include -# include -# endif -# include -#endif - -/* support multiple event loops? */ -#if EV_MULTIPLICITY -struct ev_loop; -# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */ -# define EV_P_ EV_P, /* a loop as first of multiple parameters */ -# define EV_A loop /* a loop as sole argument to a function call */ -# define EV_A_ EV_A, /* a loop as first of multiple arguments */ -# define EV_DEFAULT_UC ev_default_loop_uc_ () /* the default loop, if initialised, as sole arg */ -# define EV_DEFAULT_UC_ EV_DEFAULT_UC, /* the default loop as first of multiple arguments */ -# define EV_DEFAULT ev_default_loop (0) /* the default loop as sole arg */ -# define EV_DEFAULT_ EV_DEFAULT, /* the default loop as first of multiple arguments */ -#else -# define EV_P void -# define EV_P_ -# define EV_A -# define EV_A_ -# define EV_DEFAULT -# define EV_DEFAULT_ -# define EV_DEFAULT_UC -# define EV_DEFAULT_UC_ -# undef EV_EMBED_ENABLE -#endif - -/* EV_INLINE is used for functions in header files */ -#if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3 -# define EV_INLINE static inline -#else -# define EV_INLINE static -#endif - -/* EV_PROTOTYPES can be used to switch of prototype declarations */ -#ifndef EV_PROTOTYPES -# define EV_PROTOTYPES 1 -#endif - -/*****************************************************************************/ - -#define EV_VERSION_MAJOR 4 -#define EV_VERSION_MINOR 4 - -/* eventmask, revents, events... */ -enum { - EV_UNDEF = 0xFFFFFFFF, /* guaranteed to be invalid */ - EV_NONE = 0x00, /* no events */ - EV_READ = 0x01, /* ev_io detected read will not block */ - EV_WRITE = 0x02, /* ev_io detected write will not block */ - EV__IOFDSET = 0x80, /* internal use only */ - EV_IO = EV_READ, /* alias for type-detection */ - EV_TIMER = 0x00000100, /* timer timed out */ -#if EV_COMPAT3 - EV_TIMEOUT = EV_TIMER, /* pre 4.0 API compatibility */ -#endif - EV_PERIODIC = 0x00000200, /* periodic timer timed out */ - EV_SIGNAL = 0x00000400, /* signal was received */ - EV_CHILD = 0x00000800, /* child/pid had status change */ - EV_STAT = 0x00001000, /* stat data changed */ - EV_IDLE = 0x00002000, /* event loop is idling */ - EV_PREPARE = 0x00004000, /* event loop about to poll */ - EV_CHECK = 0x00008000, /* event loop finished poll */ - EV_EMBED = 0x00010000, /* embedded event loop needs sweep */ - EV_FORK = 0x00020000, /* event loop resumed in child */ - EV_CLEANUP = 0x00040000, /* event loop resumed in child */ - EV_ASYNC = 0x00080000, /* async intra-loop signal */ - EV_CUSTOM = 0x01000000, /* for use by user code */ - EV_ERROR = 0x80000000 /* sent when an error occurs */ -}; - -/* can be used to add custom fields to all watchers, while losing binary compatibility */ -#ifndef EV_COMMON -# define EV_COMMON void *data; -#endif - -#ifndef EV_CB_DECLARE -# define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); -#endif -#ifndef EV_CB_INVOKE -# define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents)) -#endif - -/* not official, do not use */ -#define EV_CB(type,name) void name (EV_P_ struct ev_ ## type *w, int revents) - -/* - * struct member types: - * private: you may look at them, but not change them, - * and they might not mean anything to you. - * ro: can be read anytime, but only changed when the watcher isn't active. - * rw: can be read and modified anytime, even when the watcher is active. - * - * some internal details that might be helpful for debugging: - * - * active is either 0, which means the watcher is not active, - * or the array index of the watcher (periodics, timers) - * or the array index + 1 (most other watchers) - * or simply 1 for watchers that aren't in some array. - * pending is either 0, in which case the watcher isn't, - * or the array index + 1 in the pendings array. - */ - -#if EV_MINPRI == EV_MAXPRI -# define EV_DECL_PRIORITY -#elif !defined (EV_DECL_PRIORITY) -# define EV_DECL_PRIORITY int priority; -#endif - -/* shared by all watchers */ -#define EV_WATCHER(type) \ - int active; /* private */ \ - int pending; /* private */ \ - EV_DECL_PRIORITY /* private */ \ - EV_COMMON /* rw */ \ - EV_CB_DECLARE (type) /* private */ - -#define EV_WATCHER_LIST(type) \ - EV_WATCHER (type) \ - struct ev_watcher_list *next; /* private */ - -#define EV_WATCHER_TIME(type) \ - EV_WATCHER (type) \ - ev_tstamp at; /* private */ - -/* base class, nothing to see here unless you subclass */ -typedef struct ev_watcher -{ - EV_WATCHER (ev_watcher) -} ev_watcher; - -/* base class, nothing to see here unless you subclass */ -typedef struct ev_watcher_list -{ - EV_WATCHER_LIST (ev_watcher_list) -} ev_watcher_list; - -/* base class, nothing to see here unless you subclass */ -typedef struct ev_watcher_time -{ - EV_WATCHER_TIME (ev_watcher_time) -} ev_watcher_time; - -/* invoked when fd is either EV_READable or EV_WRITEable */ -/* revent EV_READ, EV_WRITE */ -typedef struct ev_io -{ - EV_WATCHER_LIST (ev_io) - - int fd; /* ro */ - int events; /* ro */ -} ev_io; - -/* invoked after a specific time, repeatable (based on monotonic clock) */ -/* revent EV_TIMEOUT */ -typedef struct ev_timer -{ - EV_WATCHER_TIME (ev_timer) - - ev_tstamp repeat; /* rw */ -} ev_timer; - -/* invoked at some specific time, possibly repeating at regular intervals (based on UTC) */ -/* revent EV_PERIODIC */ -typedef struct ev_periodic -{ - EV_WATCHER_TIME (ev_periodic) - - ev_tstamp offset; /* rw */ - ev_tstamp interval; /* rw */ - ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now); /* rw */ -} ev_periodic; - -/* invoked when the given signal has been received */ -/* revent EV_SIGNAL */ -typedef struct ev_signal -{ - EV_WATCHER_LIST (ev_signal) - - int signum; /* ro */ -} ev_signal; - -/* invoked when sigchld is received and waitpid indicates the given pid */ -/* revent EV_CHILD */ -/* does not support priorities */ -typedef struct ev_child -{ - EV_WATCHER_LIST (ev_child) - - int flags; /* private */ - int pid; /* ro */ - int rpid; /* rw, holds the received pid */ - int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */ -} ev_child; - -#if EV_STAT_ENABLE -/* st_nlink = 0 means missing file or other error */ -# ifdef _WIN32 -typedef struct _stati64 ev_statdata; -# else -typedef struct stat ev_statdata; -# endif - -/* invoked each time the stat data changes for a given path */ -/* revent EV_STAT */ -typedef struct ev_stat -{ - EV_WATCHER_LIST (ev_stat) - - ev_timer timer; /* private */ - ev_tstamp interval; /* ro */ - const char *path; /* ro */ - ev_statdata prev; /* ro */ - ev_statdata attr; /* ro */ - - int wd; /* wd for inotify, fd for kqueue */ -} ev_stat; -#endif - -#if EV_IDLE_ENABLE -/* invoked when the nothing else needs to be done, keeps the process from blocking */ -/* revent EV_IDLE */ -typedef struct ev_idle -{ - EV_WATCHER (ev_idle) -} ev_idle; -#endif - -/* invoked for each run of the mainloop, just before the blocking call */ -/* you can still change events in any way you like */ -/* revent EV_PREPARE */ -typedef struct ev_prepare -{ - EV_WATCHER (ev_prepare) -} ev_prepare; - -/* invoked for each run of the mainloop, just after the blocking call */ -/* revent EV_CHECK */ -typedef struct ev_check -{ - EV_WATCHER (ev_check) -} ev_check; - -#if EV_FORK_ENABLE -/* the callback gets invoked before check in the child process when a fork was detected */ -/* revent EV_FORK */ -typedef struct ev_fork -{ - EV_WATCHER (ev_fork) -} ev_fork; -#endif - -#if EV_CLEANUP_ENABLE -/* is invoked just before the loop gets destroyed */ -/* revent EV_CLEANUP */ -typedef struct ev_cleanup -{ - EV_WATCHER (ev_cleanup) -} ev_cleanup; -#endif - -#if EV_EMBED_ENABLE -/* used to embed an event loop inside another */ -/* the callback gets invoked when the event loop has handled events, and can be 0 */ -typedef struct ev_embed -{ - EV_WATCHER (ev_embed) - - struct ev_loop *other; /* ro */ - ev_io io; /* private */ - ev_prepare prepare; /* private */ - ev_check check; /* unused */ - ev_timer timer; /* unused */ - ev_periodic periodic; /* unused */ - ev_idle idle; /* unused */ - ev_fork fork; /* private */ -#if EV_CLEANUP_ENABLE - ev_cleanup cleanup; /* unused */ -#endif -} ev_embed; -#endif - -#if EV_ASYNC_ENABLE -/* invoked when somebody calls ev_async_send on the watcher */ -/* revent EV_ASYNC */ -typedef struct ev_async -{ - EV_WATCHER (ev_async) - - EV_ATOMIC_T sent; /* private */ -} ev_async; - -# define ev_async_pending(w) (+(w)->sent) -#endif - -/* the presence of this union forces similar struct layout */ -union ev_any_watcher -{ - struct ev_watcher w; - struct ev_watcher_list wl; - - struct ev_io io; - struct ev_timer timer; - struct ev_periodic periodic; - struct ev_signal signal; - struct ev_child child; -#if EV_STAT_ENABLE - struct ev_stat stat; -#endif -#if EV_IDLE_ENABLE - struct ev_idle idle; -#endif - struct ev_prepare prepare; - struct ev_check check; -#if EV_FORK_ENABLE - struct ev_fork fork; -#endif -#if EV_CLEANUP_ENABLE - struct ev_cleanup cleanup; -#endif -#if EV_EMBED_ENABLE - struct ev_embed embed; -#endif -#if EV_ASYNC_ENABLE - struct ev_async async; -#endif -}; - -/* flag bits for ev_default_loop and ev_loop_new */ -enum { - /* the default */ - EVFLAG_AUTO = 0x00000000U, /* not quite a mask */ - /* flag bits */ - EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */ - EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */ - /* debugging/feature disable */ - EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */ -#if EV_COMPAT3 - EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ -#endif - EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ - EVFLAG_NOSIGMASK = 0x00400000U /* avoid modifying the signal mask */ -}; - -/* method bits to be ored together */ -enum { - EVBACKEND_SELECT = 0x00000001U, /* about anywhere */ - EVBACKEND_POLL = 0x00000002U, /* !win */ - EVBACKEND_EPOLL = 0x00000004U, /* linux */ - EVBACKEND_KQUEUE = 0x00000008U, /* bsd */ - EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */ - EVBACKEND_PORT = 0x00000020U, /* solaris 10 */ - EVBACKEND_ALL = 0x0000003FU, /* all known backends */ - EVBACKEND_MASK = 0x0000FFFFU /* all future backends */ -}; - -#if EV_PROTOTYPES -int ev_version_major (void); -int ev_version_minor (void); - -unsigned int ev_supported_backends (void); -unsigned int ev_recommended_backends (void); -unsigned int ev_embeddable_backends (void); - -ev_tstamp ev_time (void); -void ev_sleep (ev_tstamp delay); /* sleep for a while */ - -/* Sets the allocation function to use, works like realloc. - * It is used to allocate and free memory. - * If it returns zero when memory needs to be allocated, the library might abort - * or take some potentially destructive action. - * The default is your system realloc function. - */ -void ev_set_allocator (void *(*cb)(void *ptr, long size)); - -/* set the callback function to call on a - * retryable syscall error - * (such as failed select, poll, epoll_wait) - */ -void ev_set_syserr_cb (void (*cb)(const char *msg)); - -#if EV_MULTIPLICITY - -/* the default loop is the only one that handles signals and child watchers */ -/* you can call this as often as you like */ -struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)); - -EV_INLINE struct ev_loop * -ev_default_loop_uc_ (void) -{ - extern struct ev_loop *ev_default_loop_ptr; - - return ev_default_loop_ptr; -} - -EV_INLINE int -ev_is_default_loop (EV_P) -{ - return EV_A == EV_DEFAULT_UC; -} - -/* create and destroy alternative loops that don't handle signals */ -struct ev_loop *ev_loop_new (unsigned int flags EV_CPP (= 0)); - -ev_tstamp ev_now (EV_P); /* time w.r.t. timers and the eventloop, updated after each poll */ - -#else - -int ev_default_loop (unsigned int flags EV_CPP (= 0)); /* returns true when successful */ - -EV_INLINE ev_tstamp -ev_now (void) -{ - extern ev_tstamp ev_rt_now; - - return ev_rt_now; -} - -/* looks weird, but ev_is_default_loop (EV_A) still works if this exists */ -EV_INLINE int -ev_is_default_loop (void) -{ - return 1; -} - -#endif /* multiplicity */ - -/* destroy event loops, also works for the default loop */ -void ev_loop_destroy (EV_P); - -/* this needs to be called after fork, to duplicate the loop */ -/* when you want to re-use it in the child */ -/* you can call it in either the parent or the child */ -/* you can actually call it at any time, anywhere :) */ -void ev_loop_fork (EV_P); - -unsigned int ev_backend (EV_P); /* backend in use by loop */ - -void ev_now_update (EV_P); /* update event loop time */ - -#if EV_WALK_ENABLE -/* walk (almost) all watchers in the loop of a given type, invoking the */ -/* callback on every such watcher. The callback might stop the watcher, */ -/* but do nothing else with the loop */ -void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)); -#endif - -#endif /* prototypes */ - -/* ev_run flags values */ -enum { - EVRUN_NOWAIT = 1, /* do not block/wait */ - EVRUN_ONCE = 2 /* block *once* only */ -}; - -/* ev_break how values */ -enum { - EVBREAK_CANCEL = 0, /* undo unloop */ - EVBREAK_ONE = 1, /* unloop once */ - EVBREAK_ALL = 2 /* unloop all loops */ -}; - -#if EV_PROTOTYPES -void ev_run (EV_P_ int flags EV_CPP (= 0)); -void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)); /* break out of the loop */ - -/* - * ref/unref can be used to add or remove a refcount on the mainloop. every watcher - * keeps one reference. if you have a long-running watcher you never unregister that - * should not keep ev_loop from running, unref() after starting, and ref() before stopping. - */ -void ev_ref (EV_P); -void ev_unref (EV_P); - -/* - * convenience function, wait for a single event, without registering an event watcher - * if timeout is < 0, do wait indefinitely - */ -void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); - -# if EV_FEATURE_API -unsigned int ev_iteration (EV_P); /* number of loop iterations */ -unsigned int ev_depth (EV_P); /* #ev_loop enters - #ev_loop leaves */ -void ev_verify (EV_P); /* abort if loop data corrupted */ - -void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ -void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ - -/* advanced stuff for threading etc. support, see docs */ -void ev_set_userdata (EV_P_ void *data); -void *ev_userdata (EV_P); -void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)); -void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)); - -unsigned int ev_pending_count (EV_P); /* number of pending events, if any */ -void ev_invoke_pending (EV_P); /* invoke all pending watchers */ - -/* - * stop/start the timer handling. - */ -void ev_suspend (EV_P); -void ev_resume (EV_P); -#endif - -#endif - -/* these may evaluate ev multiple times, and the other arguments at most once */ -/* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ -#define ev_init(ev,cb_) do { \ - ((ev_watcher *)(void *)(ev))->active = \ - ((ev_watcher *)(void *)(ev))->pending = 0; \ - ev_set_priority ((ev), 0); \ - ev_set_cb ((ev), cb_); \ -} while (0) - -#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0) -#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0) -#define ev_periodic_set(ev,ofs_,ival_,rcb_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb = (rcb_); } while (0) -#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0) -#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0) -#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0) -#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */ -#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */ -#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */ -#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0) -#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */ -#define ev_cleanup_set(ev) /* nop, yes, this is a serious in-joke */ -#define ev_async_set(ev) /* nop, yes, this is a serious in-joke */ - -#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0) -#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0) -#define ev_periodic_init(ev,cb,ofs,ival,rcb) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(ofs),(ival),(rcb)); } while (0) -#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0) -#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0) -#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0) -#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0) -#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0) -#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0) -#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0) -#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0) -#define ev_cleanup_init(ev,cb) do { ev_init ((ev), (cb)); ev_cleanup_set ((ev)); } while (0) -#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0) - -#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ -#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ - -#define ev_cb(ev) (ev)->cb /* rw */ - -#if EV_MINPRI == EV_MAXPRI -# define ev_priority(ev) ((ev), EV_MINPRI) -# define ev_set_priority(ev,pri) ((ev), (pri)) -#else -# define ev_priority(ev) (+(((ev_watcher *)(void *)(ev))->priority)) -# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri) -#endif - -#define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at) - -#ifndef ev_set_cb -# define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_) -#endif - -/* stopping (enabling, adding) a watcher does nothing if it is already running */ -/* stopping (disabling, deleting) a watcher does nothing unless its already running */ -#if EV_PROTOTYPES - -/* feeds an event into a watcher as if the event actually occured */ -/* accepts any ev_watcher type */ -void ev_feed_event (EV_P_ void *w, int revents); -void ev_feed_fd_event (EV_P_ int fd, int revents); -#if EV_SIGNAL_ENABLE -void ev_feed_signal (int signum); -void ev_feed_signal_event (EV_P_ int signum); -#endif -void ev_invoke (EV_P_ void *w, int revents); -int ev_clear_pending (EV_P_ void *w); - -void ev_io_start (EV_P_ ev_io *w); -void ev_io_stop (EV_P_ ev_io *w); - -void ev_timer_start (EV_P_ ev_timer *w); -void ev_timer_stop (EV_P_ ev_timer *w); -/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ -void ev_timer_again (EV_P_ ev_timer *w); -/* return remaining time */ -ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w); - -#if EV_PERIODIC_ENABLE -void ev_periodic_start (EV_P_ ev_periodic *w); -void ev_periodic_stop (EV_P_ ev_periodic *w); -void ev_periodic_again (EV_P_ ev_periodic *w); -#endif - -/* only supported in the default loop */ -#if EV_SIGNAL_ENABLE -void ev_signal_start (EV_P_ ev_signal *w); -void ev_signal_stop (EV_P_ ev_signal *w); -#endif - -/* only supported in the default loop */ -# if EV_CHILD_ENABLE -void ev_child_start (EV_P_ ev_child *w); -void ev_child_stop (EV_P_ ev_child *w); -# endif - -# if EV_STAT_ENABLE -void ev_stat_start (EV_P_ ev_stat *w); -void ev_stat_stop (EV_P_ ev_stat *w); -void ev_stat_stat (EV_P_ ev_stat *w); -# endif - -# if EV_IDLE_ENABLE -void ev_idle_start (EV_P_ ev_idle *w); -void ev_idle_stop (EV_P_ ev_idle *w); -# endif - -#if EV_PREPARE_ENABLE -void ev_prepare_start (EV_P_ ev_prepare *w); -void ev_prepare_stop (EV_P_ ev_prepare *w); -#endif - -#if EV_CHECK_ENABLE -void ev_check_start (EV_P_ ev_check *w); -void ev_check_stop (EV_P_ ev_check *w); -#endif - -# if EV_FORK_ENABLE -void ev_fork_start (EV_P_ ev_fork *w); -void ev_fork_stop (EV_P_ ev_fork *w); -# endif - -# if EV_CLEANUP_ENABLE -void ev_cleanup_start (EV_P_ ev_cleanup *w); -void ev_cleanup_stop (EV_P_ ev_cleanup *w); -# endif - -# if EV_EMBED_ENABLE -/* only supported when loop to be embedded is in fact embeddable */ -void ev_embed_start (EV_P_ ev_embed *w); -void ev_embed_stop (EV_P_ ev_embed *w); -void ev_embed_sweep (EV_P_ ev_embed *w); -# endif - -# if EV_ASYNC_ENABLE -void ev_async_start (EV_P_ ev_async *w); -void ev_async_stop (EV_P_ ev_async *w); -void ev_async_send (EV_P_ ev_async *w); -# endif - -#if EV_COMPAT3 - #define EVLOOP_NONBLOCK EVRUN_NOWAIT - #define EVLOOP_ONESHOT EVRUN_ONCE - #define EVUNLOOP_CANCEL EVBREAK_CANCEL - #define EVUNLOOP_ONE EVBREAK_ONE - #define EVUNLOOP_ALL EVBREAK_ALL - #if EV_PROTOTYPES - EV_INLINE void ev_loop (EV_P_ int flags) { ev_run (EV_A_ flags); } - EV_INLINE void ev_unloop (EV_P_ int how ) { ev_break (EV_A_ how ); } - EV_INLINE void ev_default_destroy (void) { ev_loop_destroy (EV_DEFAULT); } - EV_INLINE void ev_default_fork (void) { ev_loop_fork (EV_DEFAULT); } - #if EV_FEATURE_API - EV_INLINE unsigned int ev_loop_count (EV_P) { return ev_iteration (EV_A); } - EV_INLINE unsigned int ev_loop_depth (EV_P) { return ev_depth (EV_A); } - EV_INLINE void ev_loop_verify (EV_P) { ev_verify (EV_A); } - #endif - #endif -#else - typedef struct ev_loop ev_loop; -#endif - -#endif - -EV_CPP(}) - -#endif - diff --git a/src/util/k5ev/ev_poll.c b/src/util/k5ev/ev_poll.c deleted file mode 100644 index e53ae0de93..0000000000 --- a/src/util/k5ev/ev_poll.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * libev poll fd activity backend - * - * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -#include - -void inline_size -pollidx_init (int *base, int count) -{ - /* consider using memset (.., -1, ...), which is practically guaranteed - * to work on all systems implementing poll */ - while (count--) - *base++ = -1; -} - -static void -poll_modify (EV_P_ int fd, int oev, int nev) -{ - int idx; - - if (oev == nev) - return; - - array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init); - - idx = pollidxs [fd]; - - if (idx < 0) /* need to allocate a new pollfd */ - { - pollidxs [fd] = idx = pollcnt++; - array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2); - polls [idx].fd = fd; - } - - assert (polls [idx].fd == fd); - - if (nev) - polls [idx].events = - (nev & EV_READ ? POLLIN : 0) - | (nev & EV_WRITE ? POLLOUT : 0); - else /* remove pollfd */ - { - pollidxs [fd] = -1; - - if (expect_true (idx < --pollcnt)) - { - polls [idx] = polls [pollcnt]; - pollidxs [polls [idx].fd] = idx; - } - } -} - -static void -poll_poll (EV_P_ ev_tstamp timeout) -{ - struct pollfd *p; - int res; - - EV_RELEASE_CB; - res = poll (polls, pollcnt, ev_timeout_to_ms (timeout)); - EV_ACQUIRE_CB; - - if (expect_false (res < 0)) - { - if (errno == EBADF) - fd_ebadf (EV_A); - else if (errno == ENOMEM && !syserr_cb) - fd_enomem (EV_A); - else if (errno != EINTR) - ev_syserr ("(libev) poll"); - } - else - for (p = polls; res; ++p) - { - assert (("libev: poll() returned illegal result, broken BSD kernel?", p < polls + pollcnt)); - - if (expect_false (p->revents)) /* this expect is debatable */ - { - --res; - - if (expect_false (p->revents & POLLNVAL)) - fd_kill (EV_A_ p->fd); - else - fd_event ( - EV_A_ - p->fd, - (p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) - | (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) - ); - } - } -} - -int inline_size -poll_init (EV_P_ int flags) -{ - backend_fudge = 0.; /* posix says this is zero */ - backend_modify = poll_modify; - backend_poll = poll_poll; - - pollidxs = 0; pollidxmax = 0; - polls = 0; pollmax = 0; pollcnt = 0; - - return EVBACKEND_POLL; -} - -void inline_size -poll_destroy (EV_P) -{ - ev_free (pollidxs); - ev_free (polls); -} - diff --git a/src/util/k5ev/ev_select.c b/src/util/k5ev/ev_select.c deleted file mode 100644 index 0ea9467e40..0000000000 --- a/src/util/k5ev/ev_select.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * libev select fd activity backend - * - * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -#ifndef _WIN32 -/* for unix systems */ -# include -# ifndef __hpux -/* for REAL unix systems */ -# include -# endif -#endif - -#ifndef EV_SELECT_USE_FD_SET -# ifdef NFDBITS -# define EV_SELECT_USE_FD_SET 0 -# else -# define EV_SELECT_USE_FD_SET 1 -# endif -#endif - -#if EV_SELECT_IS_WINSOCKET -# undef EV_SELECT_USE_FD_SET -# define EV_SELECT_USE_FD_SET 1 -# undef NFDBITS -# define NFDBITS 0 -#endif - -#if !EV_SELECT_USE_FD_SET -# define NFDBYTES (NFDBITS / 8) -#endif - -#include - -static void -select_modify (EV_P_ int fd, int oev, int nev) -{ - if (oev == nev) - return; - - { -#if EV_SELECT_USE_FD_SET - - #if EV_SELECT_IS_WINSOCKET - SOCKET handle = anfds [fd].handle; - #else - int handle = fd; - #endif - - assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE)); - - /* FD_SET is broken on windows (it adds the fd to a set twice or more, - * which eventually leads to overflows). Need to call it only on changes. - */ - #if EV_SELECT_IS_WINSOCKET - if ((oev ^ nev) & EV_READ) - #endif - if (nev & EV_READ) - FD_SET (handle, (fd_set *)vec_ri); - else - FD_CLR (handle, (fd_set *)vec_ri); - - #if EV_SELECT_IS_WINSOCKET - if ((oev ^ nev) & EV_WRITE) - #endif - if (nev & EV_WRITE) - FD_SET (handle, (fd_set *)vec_wi); - else - FD_CLR (handle, (fd_set *)vec_wi); - -#else - - int word = fd / NFDBITS; - fd_mask mask = 1UL << (fd % NFDBITS); - - if (expect_false (vec_max <= word)) - { - int new_max = word + 1; - - vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES); - vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */ - vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES); - vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */ - #ifdef _WIN32 - vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */ - #endif - - for (; vec_max < new_max; ++vec_max) - ((fd_mask *)vec_ri) [vec_max] = - ((fd_mask *)vec_wi) [vec_max] = 0; - } - - ((fd_mask *)vec_ri) [word] |= mask; - if (!(nev & EV_READ)) - ((fd_mask *)vec_ri) [word] &= ~mask; - - ((fd_mask *)vec_wi) [word] |= mask; - if (!(nev & EV_WRITE)) - ((fd_mask *)vec_wi) [word] &= ~mask; -#endif - } -} - -static void -select_poll (EV_P_ ev_tstamp timeout) -{ - struct timeval tv; - int res; - int fd_setsize; - - EV_RELEASE_CB; - EV_TV_SET (tv, timeout); - -#if EV_SELECT_USE_FD_SET - fd_setsize = sizeof (fd_set); -#else - fd_setsize = vec_max * NFDBYTES; -#endif - - memcpy (vec_ro, vec_ri, fd_setsize); - memcpy (vec_wo, vec_wi, fd_setsize); - -#ifdef _WIN32 - /* pass in the write set as except set. - * the idea behind this is to work around a windows bug that causes - * errors to be reported as an exception and not by setting - * the writable bit. this is so uncontrollably lame. - */ - memcpy (vec_eo, vec_wi, fd_setsize); - res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv); -#elif EV_SELECT_USE_FD_SET - fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE; - res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); -#else - res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); -#endif - EV_ACQUIRE_CB; - - if (expect_false (res < 0)) - { - #if EV_SELECT_IS_WINSOCKET - errno = WSAGetLastError (); - #endif - #ifdef WSABASEERR - /* on windows, select returns incompatible error codes, fix this */ - if (errno >= WSABASEERR && errno < WSABASEERR + 1000) - if (errno == WSAENOTSOCK) - errno = EBADF; - else - errno -= WSABASEERR; - #endif - - #ifdef _WIN32 - /* select on windows erroneously returns EINVAL when no fd sets have been - * provided (this is documented). what microsoft doesn't tell you that this bug - * exists even when the fd sets _are_ provided, so we have to check for this bug - * here and emulate by sleeping manually. - * we also get EINVAL when the timeout is invalid, but we ignore this case here - * and assume that EINVAL always means: you have to wait manually. - */ - if (errno == EINVAL) - { - ev_sleep (timeout); - return; - } - #endif - - if (errno == EBADF) - fd_ebadf (EV_A); - else if (errno == ENOMEM && !syserr_cb) - fd_enomem (EV_A); - else if (errno != EINTR) - ev_syserr ("(libev) select"); - - return; - } - -#if EV_SELECT_USE_FD_SET - - { - int fd; - - for (fd = 0; fd < anfdmax; ++fd) - if (anfds [fd].events) - { - int events = 0; - #if EV_SELECT_IS_WINSOCKET - SOCKET handle = anfds [fd].handle; - #else - int handle = fd; - #endif - - if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ; - if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE; - #ifdef _WIN32 - if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE; - #endif - - if (expect_true (events)) - fd_event (EV_A_ fd, events); - } - } - -#else - - { - int word, bit; - for (word = vec_max; word--; ) - { - fd_mask word_r = ((fd_mask *)vec_ro) [word]; - fd_mask word_w = ((fd_mask *)vec_wo) [word]; - #ifdef _WIN32 - word_w |= ((fd_mask *)vec_eo) [word]; - #endif - - if (word_r || word_w) - for (bit = NFDBITS; bit--; ) - { - fd_mask mask = 1UL << bit; - int events = 0; - - events |= word_r & mask ? EV_READ : 0; - events |= word_w & mask ? EV_WRITE : 0; - - if (expect_true (events)) - fd_event (EV_A_ word * NFDBITS + bit, events); - } - } - } - -#endif -} - -int inline_size -select_init (EV_P_ int flags) -{ - backend_fudge = 0.; /* posix says this is zero */ - backend_modify = select_modify; - backend_poll = select_poll; - -#if EV_SELECT_USE_FD_SET - vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); - vec_ro = ev_malloc (sizeof (fd_set)); - vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi); - vec_wo = ev_malloc (sizeof (fd_set)); - #ifdef _WIN32 - vec_eo = ev_malloc (sizeof (fd_set)); - #endif -#else - vec_max = 0; - vec_ri = 0; - vec_ro = 0; - vec_wi = 0; - vec_wo = 0; - #ifdef _WIN32 - vec_eo = 0; - #endif -#endif - - return EVBACKEND_SELECT; -} - -void inline_size -select_destroy (EV_P) -{ - ev_free (vec_ri); - ev_free (vec_ro); - ev_free (vec_wi); - ev_free (vec_wo); - #ifdef _WIN32 - ev_free (vec_eo); - #endif -} - - diff --git a/src/util/k5ev/ev_vars.h b/src/util/k5ev/ev_vars.h deleted file mode 100644 index 5ee3ed1b2a..0000000000 --- a/src/util/k5ev/ev_vars.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * loop member variable declarations - * - * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -#define VARx(type,name) VAR(name, type name) - -VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */ -VARx(ev_tstamp, mn_now) /* monotonic clock "now" */ -VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ - -VARx(ev_tstamp, io_blocktime) -VARx(ev_tstamp, timeout_blocktime) - -VARx(int, backend) -VARx(int, activecnt) /* total number of active events ("refcount") */ -VARx(EV_ATOMIC_T, loop_done) /* signal by ev_break */ - -VARx(int, backend_fd) -VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */ -VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev)) -VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout)) - -VARx(ANFD *, anfds) -VARx(int, anfdmax) - -VAR (pendings, ANPENDING *pendings [NUMPRI]) -VAR (pendingmax, int pendingmax [NUMPRI]) -VAR (pendingcnt, int pendingcnt [NUMPRI]) -VARx(ev_prepare, pending_w) /* dummy pending watcher */ - -/* for reverse feeding of events */ -VARx(W *, rfeeds) -VARx(int, rfeedmax) -VARx(int, rfeedcnt) - -#if EV_USE_EVENTFD || EV_GENWRAP -VARx(int, evfd) -#endif -VAR (evpipe, int evpipe [2]) -VARx(ev_io, pipe_w) - -#if !defined(_WIN32) || EV_GENWRAP -VARx(pid_t, curpid) -#endif - -VARx(char, postfork) /* true if we need to recreate kernel state after fork */ - -#if EV_USE_SELECT || EV_GENWRAP -VARx(void *, vec_ri) -VARx(void *, vec_ro) -VARx(void *, vec_wi) -VARx(void *, vec_wo) -#if defined(_WIN32) || EV_GENWRAP -VARx(void *, vec_eo) -#endif -VARx(int, vec_max) -#endif - -#if EV_USE_POLL || EV_GENWRAP -VARx(struct pollfd *, polls) -VARx(int, pollmax) -VARx(int, pollcnt) -VARx(int *, pollidxs) /* maps fds into structure indices */ -VARx(int, pollidxmax) -#endif - -#if EV_USE_EPOLL || EV_GENWRAP -VARx(struct epoll_event *, epoll_events) -VARx(int, epoll_eventmax) -VARx(int *, epoll_eperms) -VARx(int, epoll_epermcnt) -VARx(int, epoll_epermmax) -#endif - -#if EV_USE_KQUEUE || EV_GENWRAP -VARx(struct kevent *, kqueue_changes) -VARx(int, kqueue_changemax) -VARx(int, kqueue_changecnt) -VARx(struct kevent *, kqueue_events) -VARx(int, kqueue_eventmax) -#endif - -#if EV_USE_PORT || EV_GENWRAP -VARx(struct port_event *, port_events) -VARx(int, port_eventmax) -#endif - -#if EV_USE_IOCP || EV_GENWRAP -VARx(HANDLE, iocp) -#endif - -VARx(int *, fdchanges) -VARx(int, fdchangemax) -VARx(int, fdchangecnt) - -VARx(ANHE *, timers) -VARx(int, timermax) -VARx(int, timercnt) - -#if EV_PERIODIC_ENABLE || EV_GENWRAP -VARx(ANHE *, periodics) -VARx(int, periodicmax) -VARx(int, periodiccnt) -#endif - -#if EV_IDLE_ENABLE || EV_GENWRAP -VAR (idles, ev_idle **idles [NUMPRI]) -VAR (idlemax, int idlemax [NUMPRI]) -VAR (idlecnt, int idlecnt [NUMPRI]) -#endif -VARx(int, idleall) /* total number */ - -VARx(struct ev_prepare **, prepares) -VARx(int, preparemax) -VARx(int, preparecnt) - -VARx(struct ev_check **, checks) -VARx(int, checkmax) -VARx(int, checkcnt) - -#if EV_FORK_ENABLE || EV_GENWRAP -VARx(struct ev_fork **, forks) -VARx(int, forkmax) -VARx(int, forkcnt) -#endif - -#if EV_CLEANUP_ENABLE || EV_GENWRAP -VARx(struct ev_cleanup **, cleanups) -VARx(int, cleanupmax) -VARx(int, cleanupcnt) -#endif - -#if EV_ASYNC_ENABLE || EV_GENWRAP -VARx(EV_ATOMIC_T, async_pending) -VARx(struct ev_async **, asyncs) -VARx(int, asyncmax) -VARx(int, asynccnt) -#endif - -#if EV_USE_INOTIFY || EV_GENWRAP -VARx(int, fs_fd) -VARx(ev_io, fs_w) -VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ -VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) -#endif - -VARx(EV_ATOMIC_T, sig_pending) -VARx(int, nosigmask) -#if EV_USE_SIGNALFD || EV_GENWRAP -VARx(int, sigfd) -VARx(ev_io, sigfd_w) -VARx(sigset_t, sigfd_set) -#endif - -VARx(unsigned int, origflags) /* original loop flags */ - -#if EV_FEATURE_API || EV_GENWRAP -VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ -VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ - -VARx(void *, userdata) -VAR (release_cb, void (*release_cb)(EV_P)) -VAR (acquire_cb, void (*acquire_cb)(EV_P)) -VAR (invoke_cb , void (*invoke_cb) (EV_P)) -#endif - -#undef VARx - diff --git a/src/util/k5ev/ev_win32.c b/src/util/k5ev/ev_win32.c deleted file mode 100644 index 338886efe4..0000000000 --- a/src/util/k5ev/ev_win32.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * libev win32 compatibility cruft (_not_ a backend) - * - * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modifica- - * tion, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- - * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- - * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- - * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License ("GPL") version 2 or any later version, - * in which case the provisions of the GPL are applicable instead of - * the above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the BSD license, indicate your decision - * by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file under - * either the BSD or the GPL. - */ - -#ifdef _WIN32 - -/* timeb.h is actually xsi legacy functionality */ -#include - -/* note: the comment below could not be substantiated, but what would I care */ -/* MSDN says this is required to handle SIGFPE */ -/* my wild guess would be that using something floating-pointy is required */ -/* for the crt to do something about it */ -volatile double SIGFPE_REQ = 0.0f; - -/* oh, the humanity! */ -static int -ev_pipe (int filedes [2]) -{ - struct sockaddr_in addr = { 0 }; - int addr_size = sizeof (addr); - struct sockaddr_in adr2; - int adr2_size = sizeof (adr2); - SOCKET listener; - SOCKET sock [2] = { -1, -1 }; - - if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) - return -1; - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - addr.sin_port = 0; - - if (bind (listener, (struct sockaddr *)&addr, addr_size)) - goto fail; - - if (getsockname (listener, (struct sockaddr *)&addr, &addr_size)) - goto fail; - - if (listen (listener, 1)) - goto fail; - - if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) - goto fail; - - if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) - goto fail; - - if ((sock [1] = accept (listener, 0, 0)) < 0) - goto fail; - - /* windows vista returns fantasy port numbers for sockets: - * example for two interconnected tcp sockets: - * - * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364 - * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363 - * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363 - * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365 - * - * wow! tridirectional sockets! - * - * this way of checking ports seems to work: - */ - if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size)) - goto fail; - - if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size)) - goto fail; - - errno = WSAEINVAL; - if (addr_size != adr2_size - || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */ - || addr.sin_port != adr2.sin_port) - goto fail; - - closesocket (listener); - -#if EV_SELECT_IS_WINSOCKET - filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]); - filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]); -#else - /* when select isn't winsocket, we also expect socket, connect, accept etc. - * to work on fds */ - filedes [0] = sock [0]; - filedes [1] = sock [1]; -#endif - - return 0; - -fail: - closesocket (listener); - - if (sock [0] != INVALID_SOCKET) closesocket (sock [0]); - if (sock [1] != INVALID_SOCKET) closesocket (sock [1]); - - return -1; -} - -#undef pipe -#define pipe(filedes) ev_pipe (filedes) - -#define EV_HAVE_EV_TIME 1 -ev_tstamp -ev_time (void) -{ - FILETIME ft; - ULARGE_INTEGER ui; - - GetSystemTimeAsFileTime (&ft); - ui.u.LowPart = ft.dwLowDateTime; - ui.u.HighPart = ft.dwHighDateTime; - - /* msvc cannot convert ulonglong to double... yes, it is that sucky */ - return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7; -} - -#endif - diff --git a/src/util/k5ev/ev_wrap.h b/src/util/k5ev/ev_wrap.h deleted file mode 100644 index 2c195c5db4..0000000000 --- a/src/util/k5ev/ev_wrap.h +++ /dev/null @@ -1,196 +0,0 @@ -/* DO NOT EDIT, automatically generated by update_ev_wrap */ -#ifndef EV_WRAP_H -#define EV_WRAP_H -#define now_floor ((loop)->now_floor) -#define mn_now ((loop)->mn_now) -#define rtmn_diff ((loop)->rtmn_diff) -#define io_blocktime ((loop)->io_blocktime) -#define timeout_blocktime ((loop)->timeout_blocktime) -#define backend ((loop)->backend) -#define activecnt ((loop)->activecnt) -#define loop_done ((loop)->loop_done) -#define backend_fd ((loop)->backend_fd) -#define backend_fudge ((loop)->backend_fudge) -#define backend_modify ((loop)->backend_modify) -#define backend_poll ((loop)->backend_poll) -#define anfds ((loop)->anfds) -#define anfdmax ((loop)->anfdmax) -#define pendings ((loop)->pendings) -#define pendingmax ((loop)->pendingmax) -#define pendingcnt ((loop)->pendingcnt) -#define pending_w ((loop)->pending_w) -#define rfeeds ((loop)->rfeeds) -#define rfeedmax ((loop)->rfeedmax) -#define rfeedcnt ((loop)->rfeedcnt) -#define evfd ((loop)->evfd) -#define evpipe ((loop)->evpipe) -#define pipe_w ((loop)->pipe_w) -#define curpid ((loop)->curpid) -#define postfork ((loop)->postfork) -#define vec_ri ((loop)->vec_ri) -#define vec_ro ((loop)->vec_ro) -#define vec_wi ((loop)->vec_wi) -#define vec_wo ((loop)->vec_wo) -#define vec_eo ((loop)->vec_eo) -#define vec_max ((loop)->vec_max) -#define polls ((loop)->polls) -#define pollmax ((loop)->pollmax) -#define pollcnt ((loop)->pollcnt) -#define pollidxs ((loop)->pollidxs) -#define pollidxmax ((loop)->pollidxmax) -#define epoll_events ((loop)->epoll_events) -#define epoll_eventmax ((loop)->epoll_eventmax) -#define epoll_eperms ((loop)->epoll_eperms) -#define epoll_epermcnt ((loop)->epoll_epermcnt) -#define epoll_epermmax ((loop)->epoll_epermmax) -#define kqueue_changes ((loop)->kqueue_changes) -#define kqueue_changemax ((loop)->kqueue_changemax) -#define kqueue_changecnt ((loop)->kqueue_changecnt) -#define kqueue_events ((loop)->kqueue_events) -#define kqueue_eventmax ((loop)->kqueue_eventmax) -#define port_events ((loop)->port_events) -#define port_eventmax ((loop)->port_eventmax) -#define iocp ((loop)->iocp) -#define fdchanges ((loop)->fdchanges) -#define fdchangemax ((loop)->fdchangemax) -#define fdchangecnt ((loop)->fdchangecnt) -#define timers ((loop)->timers) -#define timermax ((loop)->timermax) -#define timercnt ((loop)->timercnt) -#define periodics ((loop)->periodics) -#define periodicmax ((loop)->periodicmax) -#define periodiccnt ((loop)->periodiccnt) -#define idles ((loop)->idles) -#define idlemax ((loop)->idlemax) -#define idlecnt ((loop)->idlecnt) -#define idleall ((loop)->idleall) -#define prepares ((loop)->prepares) -#define preparemax ((loop)->preparemax) -#define preparecnt ((loop)->preparecnt) -#define checks ((loop)->checks) -#define checkmax ((loop)->checkmax) -#define checkcnt ((loop)->checkcnt) -#define forks ((loop)->forks) -#define forkmax ((loop)->forkmax) -#define forkcnt ((loop)->forkcnt) -#define cleanups ((loop)->cleanups) -#define cleanupmax ((loop)->cleanupmax) -#define cleanupcnt ((loop)->cleanupcnt) -#define async_pending ((loop)->async_pending) -#define asyncs ((loop)->asyncs) -#define asyncmax ((loop)->asyncmax) -#define asynccnt ((loop)->asynccnt) -#define fs_fd ((loop)->fs_fd) -#define fs_w ((loop)->fs_w) -#define fs_2625 ((loop)->fs_2625) -#define fs_hash ((loop)->fs_hash) -#define sig_pending ((loop)->sig_pending) -#define nosigmask ((loop)->nosigmask) -#define sigfd ((loop)->sigfd) -#define sigfd_w ((loop)->sigfd_w) -#define sigfd_set ((loop)->sigfd_set) -#define origflags ((loop)->origflags) -#define loop_count ((loop)->loop_count) -#define loop_depth ((loop)->loop_depth) -#define userdata ((loop)->userdata) -#define release_cb ((loop)->release_cb) -#define acquire_cb ((loop)->acquire_cb) -#define invoke_cb ((loop)->invoke_cb) -#else -#undef EV_WRAP_H -#undef now_floor -#undef mn_now -#undef rtmn_diff -#undef io_blocktime -#undef timeout_blocktime -#undef backend -#undef activecnt -#undef loop_done -#undef backend_fd -#undef backend_fudge -#undef backend_modify -#undef backend_poll -#undef anfds -#undef anfdmax -#undef pendings -#undef pendingmax -#undef pendingcnt -#undef pending_w -#undef rfeeds -#undef rfeedmax -#undef rfeedcnt -#undef evfd -#undef evpipe -#undef pipe_w -#undef curpid -#undef postfork -#undef vec_ri -#undef vec_ro -#undef vec_wi -#undef vec_wo -#undef vec_eo -#undef vec_max -#undef polls -#undef pollmax -#undef pollcnt -#undef pollidxs -#undef pollidxmax -#undef epoll_events -#undef epoll_eventmax -#undef epoll_eperms -#undef epoll_epermcnt -#undef epoll_epermmax -#undef kqueue_changes -#undef kqueue_changemax -#undef kqueue_changecnt -#undef kqueue_events -#undef kqueue_eventmax -#undef port_events -#undef port_eventmax -#undef iocp -#undef fdchanges -#undef fdchangemax -#undef fdchangecnt -#undef timers -#undef timermax -#undef timercnt -#undef periodics -#undef periodicmax -#undef periodiccnt -#undef idles -#undef idlemax -#undef idlecnt -#undef idleall -#undef prepares -#undef preparemax -#undef preparecnt -#undef checks -#undef checkmax -#undef checkcnt -#undef forks -#undef forkmax -#undef forkcnt -#undef cleanups -#undef cleanupmax -#undef cleanupcnt -#undef async_pending -#undef asyncs -#undef asyncmax -#undef asynccnt -#undef fs_fd -#undef fs_w -#undef fs_2625 -#undef fs_hash -#undef sig_pending -#undef nosigmask -#undef sigfd -#undef sigfd_w -#undef sigfd_set -#undef origflags -#undef loop_count -#undef loop_depth -#undef userdata -#undef release_cb -#undef acquire_cb -#undef invoke_cb -#endif diff --git a/src/util/k5ev/libverto-k5ev.exports b/src/util/k5ev/libverto-k5ev.exports deleted file mode 100644 index 7907fbef70..0000000000 --- a/src/util/k5ev/libverto-k5ev.exports +++ /dev/null @@ -1,3 +0,0 @@ -verto_default_k5ev -verto_module_table_k5ev -verto_new_k5ev diff --git a/src/util/k5ev/verto-k5ev.c b/src/util/k5ev/verto-k5ev.c deleted file mode 100644 index 35c94d66ed..0000000000 --- a/src/util/k5ev/verto-k5ev.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2011 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * An edited version of verto-libev.c, using an embedded libev with renamed - * symbols. The corresponding version of verto-libev.c is stored in this - * directory for reference, although it is not built here. - */ - -#include -#include -#include - -#include "verto-k5ev.h" -#include -#include "rename.h" -#include "autoconf.h" -#define EV_STANDALONE 1 -/* Avoid using clock_gettime, which would create a dependency on librt. */ -#define EV_USE_MONOTONIC 0 -#define EV_USE_REALTIME 0 -#define EV_FEATURES 0x5f /* Everything but back ends */ -#ifdef HAVE_POLL_H -#define EV_USE_POLL 1 -#endif -/* ev.c explicitly disables poll() on Mac or FreeBSD; fall back to select(). */ -#define EV_USE_SELECT 1 -#include "ev.c" - -static verto_mod_ctx * -k5ev_ctx_new(void) -{ - return ev_loop_new(EVFLAG_AUTO); -} - -static verto_mod_ctx * -k5ev_ctx_default(void) -{ - return ev_default_loop(EVFLAG_AUTO); -} - -static void -k5ev_ctx_free(verto_mod_ctx *ctx) -{ - if (ctx != EV_DEFAULT) - ev_loop_destroy(ctx); -} - -static void -k5ev_ctx_run(verto_mod_ctx *ctx) -{ - ev_run(ctx, 0); -} - -static void -k5ev_ctx_run_once(verto_mod_ctx *ctx) -{ - ev_run(ctx, EVRUN_ONCE); -} - -static void -k5ev_ctx_break(verto_mod_ctx *ctx) -{ - ev_break(ctx, EVBREAK_ONE); -} - -static void -k5ev_ctx_reinitialize(verto_mod_ctx *ctx) -{ - ev_loop_fork(ctx); -} - -static void -libev_callback(EV_P_ ev_watcher *w, int revents) -{ - verto_ev_flag state = VERTO_EV_FLAG_NONE; - - if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD) - verto_set_proc_status(w->data, ((ev_child*) w)->rstatus); - - if (revents & EV_READ) - state |= VERTO_EV_FLAG_IO_READ; - if (revents & EV_WRITE) - state |= VERTO_EV_FLAG_IO_WRITE; - if (revents & EV_ERROR) - state |= VERTO_EV_FLAG_IO_ERROR; - - verto_set_fd_state(w->data, state); - verto_fire(w->data); -} - -static void -k5ev_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev, - verto_mod_ev *evpriv) -{ - if (verto_get_type(ev) == VERTO_EV_TYPE_IO) { - int events = EV_NONE; - - if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ) - events |= EV_READ; - if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE) - events |= EV_WRITE; - - ev_io_stop(ctx, (ev_io*) evpriv); - ev_io_set(((ev_io*) evpriv), verto_get_fd(ev), events); - ev_io_start(ctx, (ev_io*) evpriv); - } -} - -#define setuptype(type, ...) \ - w.type = malloc(sizeof(ev_ ## type)); \ - if (w.type) { \ - ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \ - ev_ ## type ## _start(ctx, w.type); \ - } \ - break - -static verto_mod_ev * -k5ev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags) -{ - union { - ev_watcher *watcher; - ev_io *io; - ev_timer *timer; - ev_idle *idle; - ev_signal *signal; - ev_child *child; - } w; - ev_tstamp interval; - - w.watcher = NULL; - *flags |= VERTO_EV_FLAG_PERSIST; - switch (verto_get_type(ev)) { - case VERTO_EV_TYPE_IO: - setuptype(io, libev_callback, verto_get_fd(ev), EV_NONE); - case VERTO_EV_TYPE_TIMEOUT: - interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0; - setuptype(timer, libev_callback, interval, interval); - case VERTO_EV_TYPE_IDLE: - setuptype(idle, libev_callback); - case VERTO_EV_TYPE_SIGNAL: - setuptype(signal, libev_callback, verto_get_signal(ev)); - case VERTO_EV_TYPE_CHILD: - *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ - setuptype(child, libev_callback, verto_get_proc(ev), 0); - default: - break; /* Not supported */ - } - - if (w.watcher) { - w.watcher->data = (void*) ev; - k5ev_ctx_set_flags(ctx, ev, w.watcher); - } - return w.watcher; -} - -static void -k5ev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv) -{ - switch (verto_get_type(ev)) { - case VERTO_EV_TYPE_IO: - ev_io_stop(ctx, (ev_io*) evpriv); - break; - case VERTO_EV_TYPE_TIMEOUT: - ev_timer_stop(ctx, (ev_timer*) evpriv); - break; - case VERTO_EV_TYPE_IDLE: - ev_idle_stop(ctx, (ev_idle*) evpriv); - break; - case VERTO_EV_TYPE_SIGNAL: - ev_signal_stop(ctx, (ev_signal*) evpriv); - break; - case VERTO_EV_TYPE_CHILD: - ev_child_stop(ctx, (ev_child*) evpriv); - break; - default: - break; - } - - free(evpriv); -} - -VERTO_MODULE(k5ev, NULL, - VERTO_EV_TYPE_IO | - VERTO_EV_TYPE_TIMEOUT | - VERTO_EV_TYPE_IDLE | - VERTO_EV_TYPE_SIGNAL | - VERTO_EV_TYPE_CHILD); - -verto_ctx * -verto_convert_k5ev(struct ev_loop* loop) -{ - return verto_convert(k5ev, 0, loop); -} diff --git a/src/util/k5ev/verto-k5ev.h b/src/util/k5ev/verto-k5ev.h deleted file mode 100644 index 0b1ad192c3..0000000000 --- a/src/util/k5ev/verto-k5ev.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef VERTO_K5EV_H_ -#define VERTO_K5EV_H_ - -#include - -verto_ctx *verto_new_k5ev(void); -verto_ctx *verto_default_k5ev(void); - -#endif /* VERTO_K5EV_H_ */ diff --git a/src/util/k5ev/verto-libev.c b/src/util/k5ev/verto-libev.c deleted file mode 100644 index 9c7c32449c..0000000000 --- a/src/util/k5ev/verto-libev.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2011 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include - -#include -#define VERTO_MODULE_TYPES -typedef struct ev_loop verto_mod_ctx; -typedef ev_watcher verto_mod_ev; -#include - -static verto_mod_ctx * -libev_ctx_new(void) -{ - return ev_loop_new(EVFLAG_AUTO); -} - -static verto_mod_ctx * -libev_ctx_default(void) -{ - return ev_default_loop(EVFLAG_AUTO); -} - -static void -libev_ctx_free(verto_mod_ctx *ctx) -{ - if (ctx != EV_DEFAULT) - ev_loop_destroy(ctx); -} - -static void -libev_ctx_run(verto_mod_ctx *ctx) -{ - ev_run(ctx, 0); -} - -static void -libev_ctx_run_once(verto_mod_ctx *ctx) -{ - ev_run(ctx, EVRUN_ONCE); -} - -static void -libev_ctx_break(verto_mod_ctx *ctx) -{ - ev_break(ctx, EVBREAK_ONE); -} - -static void -libev_ctx_reinitialize(verto_mod_ctx *ctx) -{ - ev_loop_fork(ctx); -} - -static void -libev_callback(EV_P_ ev_watcher *w, int revents) -{ - verto_ev_flag state = VERTO_EV_FLAG_NONE; - - if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD) - verto_set_proc_status(w->data, ((ev_child*) w)->rstatus); - - if (revents & EV_READ) - state |= VERTO_EV_FLAG_IO_READ; - if (revents & EV_WRITE) - state |= VERTO_EV_FLAG_IO_WRITE; - if (revents & EV_ERROR) - state |= VERTO_EV_FLAG_IO_ERROR; - - verto_set_fd_state(w->data, state); - verto_fire(w->data); -} - -static void -libev_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev, - verto_mod_ev *evpriv) -{ - if (verto_get_type(ev) == VERTO_EV_TYPE_IO) { - int events = EV_NONE; - - if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ) - events |= EV_READ; - if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE) - events |= EV_WRITE; - - ev_io_stop(ctx, (ev_io*) evpriv); - ev_io_set(((ev_io*) evpriv), verto_get_fd(ev), events); - ev_io_start(ctx, (ev_io*) evpriv); - } -} - -#define setuptype(type, ...) \ - w.type = malloc(sizeof(ev_ ## type)); \ - if (w.type) { \ - ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \ - ev_ ## type ## _start(ctx, w.type); \ - } \ - break - -static verto_mod_ev * -libev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags) -{ - union { - ev_watcher *watcher; - ev_io *io; - ev_timer *timer; - ev_idle *idle; - ev_signal *signal; - ev_child *child; - } w; - ev_tstamp interval; - - w.watcher = NULL; - *flags |= VERTO_EV_FLAG_PERSIST; - switch (verto_get_type(ev)) { - case VERTO_EV_TYPE_IO: - setuptype(io, libev_callback, verto_get_fd(ev), EV_NONE); - case VERTO_EV_TYPE_TIMEOUT: - interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0; - setuptype(timer, libev_callback, interval, interval); - case VERTO_EV_TYPE_IDLE: - setuptype(idle, libev_callback); - case VERTO_EV_TYPE_SIGNAL: - setuptype(signal, libev_callback, verto_get_signal(ev)); - case VERTO_EV_TYPE_CHILD: - *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ - setuptype(child, libev_callback, verto_get_proc(ev), 0); - default: - break; /* Not supported */ - } - - if (w.watcher) { - w.watcher->data = (void*) ev; - libev_ctx_set_flags(ctx, ev, w.watcher); - } - return w.watcher; -} - -static void -libev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv) -{ - switch (verto_get_type(ev)) { - case VERTO_EV_TYPE_IO: - ev_io_stop(ctx, (ev_io*) evpriv); - break; - case VERTO_EV_TYPE_TIMEOUT: - ev_timer_stop(ctx, (ev_timer*) evpriv); - break; - case VERTO_EV_TYPE_IDLE: - ev_idle_stop(ctx, (ev_idle*) evpriv); - break; - case VERTO_EV_TYPE_SIGNAL: - ev_signal_stop(ctx, (ev_signal*) evpriv); - break; - case VERTO_EV_TYPE_CHILD: - ev_child_stop(ctx, (ev_child*) evpriv); - break; - default: - break; - } - - free(evpriv); -} - -VERTO_MODULE(libev, ev_loop_new, - VERTO_EV_TYPE_IO | - VERTO_EV_TYPE_TIMEOUT | - VERTO_EV_TYPE_IDLE | - VERTO_EV_TYPE_SIGNAL | - VERTO_EV_TYPE_CHILD); - -verto_ctx * -verto_convert_libev(struct ev_loop* loop) -{ - return verto_convert(libev, 0, loop); -} diff --git a/src/util/verto/Makefile.in b/src/util/verto/Makefile.in index f7206c83d4..ff1bd1af71 100644 --- a/src/util/verto/Makefile.in +++ b/src/util/verto/Makefile.in @@ -6,32 +6,38 @@ LIBBASE=verto LIBMAJOR=0 LIBMINOR=0 -LOCALINCLUDES=-I$(srcdir) -DEFINES=-DDEFAULT_LIBRARY=\"k5ev\" +LOCALINCLUDES=-I$(srcdir) -I. +DEFINES=-DDEFAULT_LIBRARY=\"k5ev\" -DBUILTIN_MODULE=k5ev # Turn off extra warnings since we're not going to clean up libverto's code. WARN_CFLAGS= -STLIBOBJS=verto.o module.o -LIBOBJS=$(OUTPRE)verto.$(OBJEXT) $(OUTPRE)module.$(OBJEXT) -SRCS=verto.c module.c +STLIBOBJS=verto.o module.o verto-k5ev.o +LIBOBJS=$(OUTPRE)verto.$(OBJEXT) \ + $(OUTPRE)module.$(OBJEXT) \ + $(OUTPRE)verto-k5ev.$(OBJEXT) +SRCS=verto.c module.c verto-k5ev.c STOBJLISTS=OBJS.ST -SHLIB_EXPLIBS= $(DL_LIB) $(LIBS) +SHLIB_EXPLIBS= $(LIBS) -lm # libm needed for ceil() currently. SHLIB_DIRS= SHLIB_RDIRS=$(KRB5_LIBDIR) VERTO_HDR=$(BUILDTOP)$(S)include$(S)verto.h +rename.h: $(srcdir)/Symbols.ev + $(RM) $@ + $(SED) -e 's/.*/#define & k5&/' < $(srcdir)/Symbols.ev > $@ + all-unix:: all-liblinks includes install-unix:: install-libs clean-unix:: clean-liblinks clean-libs clean-libobjs - $(RM) $(VERTO_HDR) + $(RM) $(VERTO_HDR) rename.h includes:: $(VERTO_HDR) -depend:: $(VERTO_HDR) +depend:: $(VERTO_HDR) rename.h $(VERTO_HDR): $(srcdir)/verto.h $(RM) $@ diff --git a/src/util/verto/README b/src/util/verto/README index 8e47610565..6de645f6fb 100644 --- a/src/util/verto/README +++ b/src/util/verto/README @@ -1,6 +1,40 @@ -This directory builds a verto library with only a private back-end -module, for use when the system has no installed verto library. +This directory builds a verto library with only a private built-in +module, for use when the system has no installed verto library. The +bundled verto cannot dynamically load modules. From the upstream +libverto, we take only verto.c and verto-libev.c, and we only build +the former; the latter is stored here for comparison purposes. We use +a stub implementation of module.c to disable dynamic loading support. -The libverto upstream project page is at: +This private module uses an embedded libev with renamed symbols (so we +don't leak libev symbols into the namespace on platforms where we +can't control the export list). libev has built-in support for this +kind of embedding, so we don't have to modify the libev sources. +Following libev's documentation, the following files have been copied +from the ev sources: + + ev.h + ev_vars.h + ev_wrap.h + ev.c + ev_select.c + ev_poll.c + ev_win32.c + Symbols.ev + +(Symbols.ev wasn't included in the 4.04 tar file due to an oversight, +so it is taken from the appropriate tag in libev's source repository.) + +To rename the exported symbols, we create rename.h from Symbols.ev. +We also use Symbols.ev to construct the library export list. +(Renaming libev's symbols would be unnecessary if libev's embedding +had support for making its API symbols static, but it currently does +not.) The source file verto-k5ev.c wraps ev.c with appropriate +embedding defines, and then defines the libverto module functions +using the slightly modified contents of libverto's verto-libev.c. The +resulting module table is embedded into verto.c using the +BUILTIN_MODULE define. + +The libverto and libev upstream project pages are at: https://fedorahosted.org/libverto/ + http://software.schmorp.de/pkg/libev.html diff --git a/src/util/verto/Symbols.ev b/src/util/verto/Symbols.ev new file mode 100644 index 0000000000..7a29a75cba --- /dev/null +++ b/src/util/verto/Symbols.ev @@ -0,0 +1,73 @@ +ev_async_send +ev_async_start +ev_async_stop +ev_backend +ev_break +ev_check_start +ev_check_stop +ev_child_start +ev_child_stop +ev_cleanup_start +ev_cleanup_stop +ev_clear_pending +ev_default_loop +ev_default_loop_ptr +ev_depth +ev_embed_start +ev_embed_stop +ev_embed_sweep +ev_embeddable_backends +ev_feed_event +ev_feed_fd_event +ev_feed_signal +ev_feed_signal_event +ev_fork_start +ev_fork_stop +ev_idle_start +ev_idle_stop +ev_invoke +ev_invoke_pending +ev_io_start +ev_io_stop +ev_iteration +ev_loop_destroy +ev_loop_fork +ev_loop_new +ev_now +ev_now_update +ev_once +ev_pending_count +ev_periodic_again +ev_periodic_start +ev_periodic_stop +ev_prepare_start +ev_prepare_stop +ev_recommended_backends +ev_ref +ev_resume +ev_run +ev_set_allocator +ev_set_invoke_pending_cb +ev_set_io_collect_interval +ev_set_loop_release_cb +ev_set_syserr_cb +ev_set_timeout_collect_interval +ev_set_userdata +ev_signal_start +ev_signal_stop +ev_sleep +ev_stat_start +ev_stat_stat +ev_stat_stop +ev_supported_backends +ev_suspend +ev_time +ev_timer_again +ev_timer_remaining +ev_timer_start +ev_timer_stop +ev_unref +ev_userdata +ev_verify +ev_version_major +ev_version_minor diff --git a/src/util/verto/deps b/src/util/verto/deps index dad2f3aa63..3424d30382 100644 --- a/src/util/verto/deps +++ b/src/util/verto/deps @@ -4,3 +4,7 @@ verto.so verto.po $(OUTPRE)verto.$(OBJEXT): $(VERTO_DEPS) \ module.h verto-module.h verto.c module.so module.po $(OUTPRE)module.$(OBJEXT): module.c +verto-k5ev.so verto-k5ev.po $(OUTPRE)verto-k5ev.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(VERTO_DEPS) ev.c ev.h \ + ev_poll.c ev_select.c ev_vars.h ev_wrap.h rename.h \ + verto-k5ev.c verto-module.h diff --git a/src/util/verto/ev.c b/src/util/verto/ev.c new file mode 100644 index 0000000000..4187b18af7 --- /dev/null +++ b/src/util/verto/ev.c @@ -0,0 +1,3913 @@ +/* + * libev event processing core, watcher management + * + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +/* this big block deduces configuration from config.h */ +#ifndef EV_STANDALONE +# ifdef EV_CONFIG_H +# include EV_CONFIG_H +# else +# include "config.h" +# endif + +# if HAVE_CLOCK_SYSCALL +# ifndef EV_USE_CLOCK_SYSCALL +# define EV_USE_CLOCK_SYSCALL 1 +# ifndef EV_USE_REALTIME +# define EV_USE_REALTIME 0 +# endif +# ifndef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 1 +# endif +# endif +# elif !defined(EV_USE_CLOCK_SYSCALL) +# define EV_USE_CLOCK_SYSCALL 0 +# endif + +# if HAVE_CLOCK_GETTIME +# ifndef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 1 +# endif +# ifndef EV_USE_REALTIME +# define EV_USE_REALTIME 0 +# endif +# else +# ifndef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 0 +# endif +# ifndef EV_USE_REALTIME +# define EV_USE_REALTIME 0 +# endif +# endif + +# if HAVE_NANOSLEEP +# ifndef EV_USE_NANOSLEEP +# define EV_USE_NANOSLEEP EV_FEATURE_OS +# endif +# else +# undef EV_USE_NANOSLEEP +# define EV_USE_NANOSLEEP 0 +# endif + +# if HAVE_SELECT && HAVE_SYS_SELECT_H +# ifndef EV_USE_SELECT +# define EV_USE_SELECT EV_FEATURE_BACKENDS +# endif +# else +# undef EV_USE_SELECT +# define EV_USE_SELECT 0 +# endif + +# if HAVE_POLL && HAVE_POLL_H +# ifndef EV_USE_POLL +# define EV_USE_POLL EV_FEATURE_BACKENDS +# endif +# else +# undef EV_USE_POLL +# define EV_USE_POLL 0 +# endif + +# if HAVE_EPOLL_CTL && HAVE_SYS_EPOLL_H +# ifndef EV_USE_EPOLL +# define EV_USE_EPOLL EV_FEATURE_BACKENDS +# endif +# else +# undef EV_USE_EPOLL +# define EV_USE_EPOLL 0 +# endif + +# if HAVE_KQUEUE && HAVE_SYS_EVENT_H +# ifndef EV_USE_KQUEUE +# define EV_USE_KQUEUE EV_FEATURE_BACKENDS +# endif +# else +# undef EV_USE_KQUEUE +# define EV_USE_KQUEUE 0 +# endif + +# if HAVE_PORT_H && HAVE_PORT_CREATE +# ifndef EV_USE_PORT +# define EV_USE_PORT EV_FEATURE_BACKENDS +# endif +# else +# undef EV_USE_PORT +# define EV_USE_PORT 0 +# endif + +# if HAVE_INOTIFY_INIT && HAVE_SYS_INOTIFY_H +# ifndef EV_USE_INOTIFY +# define EV_USE_INOTIFY EV_FEATURE_OS +# endif +# else +# undef EV_USE_INOTIFY +# define EV_USE_INOTIFY 0 +# endif + +# if HAVE_SIGNALFD && HAVE_SYS_SIGNALFD_H +# ifndef EV_USE_SIGNALFD +# define EV_USE_SIGNALFD EV_FEATURE_OS +# endif +# else +# undef EV_USE_SIGNALFD +# define EV_USE_SIGNALFD 0 +# endif + +# if HAVE_EVENTFD +# ifndef EV_USE_EVENTFD +# define EV_USE_EVENTFD EV_FEATURE_OS +# endif +# else +# undef EV_USE_EVENTFD +# define EV_USE_EVENTFD 0 +# endif + +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef EV_H +# include EV_H +#else +# include "ev.h" +#endif + +EV_CPP(extern "C" {) + +#ifndef _WIN32 +# include +# include +# include +#else +# include +# define WIN32_LEAN_AND_MEAN +# include +# ifndef EV_SELECT_IS_WINSOCKET +# define EV_SELECT_IS_WINSOCKET 1 +# endif +# undef EV_AVOID_STDIO +#endif + +/* OS X, in its infinite idiocy, actually HARDCODES + * a limit of 1024 into their select. Where people have brains, + * OS X engineers apparently have a vacuum. Or maybe they were + * ordered to have a vacuum, or they do anything for money. + * This might help. Or not. + */ +#define _DARWIN_UNLIMITED_SELECT 1 + +/* this block tries to deduce configuration from header-defined symbols and defaults */ + +/* try to deduce the maximum number of signals on this platform */ +#if defined (EV_NSIG) +/* use what's provided */ +#elif defined (NSIG) +# define EV_NSIG (NSIG) +#elif defined(_NSIG) +# define EV_NSIG (_NSIG) +#elif defined (SIGMAX) +# define EV_NSIG (SIGMAX+1) +#elif defined (SIG_MAX) +# define EV_NSIG (SIG_MAX+1) +#elif defined (_SIG_MAX) +# define EV_NSIG (_SIG_MAX+1) +#elif defined (MAXSIG) +# define EV_NSIG (MAXSIG+1) +#elif defined (MAX_SIG) +# define EV_NSIG (MAX_SIG+1) +#elif defined (SIGARRAYSIZE) +# define EV_NSIG (SIGARRAYSIZE) /* Assume ary[SIGARRAYSIZE] */ +#elif defined (_sys_nsig) +# define EV_NSIG (_sys_nsig) /* Solaris 2.5 */ +#else +# error "unable to find value for NSIG, please report" +/* to make it compile regardless, just remove the above line, */ +/* but consider reporting it, too! :) */ +# define EV_NSIG 65 +#endif + +#ifndef EV_USE_CLOCK_SYSCALL +# if __linux && __GLIBC__ >= 2 +# define EV_USE_CLOCK_SYSCALL EV_FEATURE_OS +# else +# define EV_USE_CLOCK_SYSCALL 0 +# endif +#endif + +#ifndef EV_USE_MONOTONIC +# if defined (_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 +# define EV_USE_MONOTONIC EV_FEATURE_OS +# else +# define EV_USE_MONOTONIC 0 +# endif +#endif + +#ifndef EV_USE_REALTIME +# define EV_USE_REALTIME !EV_USE_CLOCK_SYSCALL +#endif + +#ifndef EV_USE_NANOSLEEP +# if _POSIX_C_SOURCE >= 199309L +# define EV_USE_NANOSLEEP EV_FEATURE_OS +# else +# define EV_USE_NANOSLEEP 0 +# endif +#endif + +#ifndef EV_USE_SELECT +# define EV_USE_SELECT EV_FEATURE_BACKENDS +#endif + +#ifndef EV_USE_POLL +# ifdef _WIN32 +# define EV_USE_POLL 0 +# else +# define EV_USE_POLL EV_FEATURE_BACKENDS +# endif +#endif + +#ifndef EV_USE_EPOLL +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4)) +# define EV_USE_EPOLL EV_FEATURE_BACKENDS +# else +# define EV_USE_EPOLL 0 +# endif +#endif + +#ifndef EV_USE_KQUEUE +# define EV_USE_KQUEUE 0 +#endif + +#ifndef EV_USE_PORT +# define EV_USE_PORT 0 +#endif + +#ifndef EV_USE_INOTIFY +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4)) +# define EV_USE_INOTIFY EV_FEATURE_OS +# else +# define EV_USE_INOTIFY 0 +# endif +#endif + +#ifndef EV_PID_HASHSIZE +# define EV_PID_HASHSIZE EV_FEATURE_DATA ? 16 : 1 +#endif + +#ifndef EV_INOTIFY_HASHSIZE +# define EV_INOTIFY_HASHSIZE EV_FEATURE_DATA ? 16 : 1 +#endif + +#ifndef EV_USE_EVENTFD +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) +# define EV_USE_EVENTFD EV_FEATURE_OS +# else +# define EV_USE_EVENTFD 0 +# endif +#endif + +#ifndef EV_USE_SIGNALFD +# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) +# define EV_USE_SIGNALFD EV_FEATURE_OS +# else +# define EV_USE_SIGNALFD 0 +# endif +#endif + +#if 0 /* debugging */ +# define EV_VERIFY 3 +# define EV_USE_4HEAP 1 +# define EV_HEAP_CACHE_AT 1 +#endif + +#ifndef EV_VERIFY +# define EV_VERIFY (EV_FEATURE_API ? 1 : 0) +#endif + +#ifndef EV_USE_4HEAP +# define EV_USE_4HEAP EV_FEATURE_DATA +#endif + +#ifndef EV_HEAP_CACHE_AT +# define EV_HEAP_CACHE_AT EV_FEATURE_DATA +#endif + +/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ +/* which makes programs even slower. might work on other unices, too. */ +#if EV_USE_CLOCK_SYSCALL +# include +# ifdef SYS_clock_gettime +# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) +# undef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 1 +# else +# undef EV_USE_CLOCK_SYSCALL +# define EV_USE_CLOCK_SYSCALL 0 +# endif +#endif + +/* this block fixes any misconfiguration where we know we run into trouble otherwise */ + +#ifdef _AIX +/* AIX has a completely broken poll.h header */ +# undef EV_USE_POLL +# define EV_USE_POLL 0 +#endif + +#ifndef CLOCK_MONOTONIC +# undef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 0 +#endif + +#ifndef CLOCK_REALTIME +# undef EV_USE_REALTIME +# define EV_USE_REALTIME 0 +#endif + +#if !EV_STAT_ENABLE +# undef EV_USE_INOTIFY +# define EV_USE_INOTIFY 0 +#endif + +#if !EV_USE_NANOSLEEP +/* hp-ux has it in sys/time.h, which we unconditionally include above */ +# if !defined(_WIN32) && !defined(__hpux) +# include +# endif +#endif + +#if EV_USE_INOTIFY +# include +# include +/* some very old inotify.h headers don't have IN_DONT_FOLLOW */ +# ifndef IN_DONT_FOLLOW +# undef EV_USE_INOTIFY +# define EV_USE_INOTIFY 0 +# endif +#endif + +#if EV_SELECT_IS_WINSOCKET +# include +#endif + +#if EV_USE_EVENTFD +/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ +# include +# ifndef EFD_NONBLOCK +# define EFD_NONBLOCK O_NONBLOCK +# endif +# ifndef EFD_CLOEXEC +# ifdef O_CLOEXEC +# define EFD_CLOEXEC O_CLOEXEC +# else +# define EFD_CLOEXEC 02000000 +# endif +# endif +EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags); +#endif + +#if EV_USE_SIGNALFD +/* our minimum requirement is glibc 2.7 which has the stub, but not the header */ +# include +# ifndef SFD_NONBLOCK +# define SFD_NONBLOCK O_NONBLOCK +# endif +# ifndef SFD_CLOEXEC +# ifdef O_CLOEXEC +# define SFD_CLOEXEC O_CLOEXEC +# else +# define SFD_CLOEXEC 02000000 +# endif +# endif +EV_CPP (extern "C") int signalfd (int fd, const sigset_t *mask, int flags); + +struct signalfd_siginfo +{ + uint32_t ssi_signo; + char pad[128 - sizeof (uint32_t)]; +}; +#endif + +/**/ + +#if EV_VERIFY >= 3 +# define EV_FREQUENT_CHECK ev_verify (EV_A) +#else +# define EV_FREQUENT_CHECK do { } while (0) +#endif + +/* + * This is used to avoid floating point rounding problems. + * It is added to ev_rt_now when scheduling periodics + * to ensure progress, time-wise, even when rounding + * errors are against us. + * This value is good at least till the year 4000. + * Better solutions welcome. + */ +#define TIME_EPSILON 0.0001220703125 /* 1/8192 */ + +#define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */ +#define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */ + +#define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec = (long)((t - tv.tv_sec) * 1e6); } while (0) +#define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec = (long)((t - ts.tv_sec) * 1e9); } while (0) + +#if __GNUC__ >= 4 +# define expect(expr,value) __builtin_expect ((expr),(value)) +# define noinline __attribute__ ((noinline)) +#else +# define expect(expr,value) (expr) +# define noinline +# if __STDC_VERSION__ < 199901L && __GNUC__ < 2 +# define inline +# endif +#endif + +#define expect_false(expr) expect ((expr) != 0, 0) +#define expect_true(expr) expect ((expr) != 0, 1) +#define inline_size static inline + +#if EV_FEATURE_CODE +# define inline_speed static inline +#else +# define inline_speed static noinline +#endif + +#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) + +#if EV_MINPRI == EV_MAXPRI +# define ABSPRI(w) (((W)w), 0) +#else +# define ABSPRI(w) (((W)w)->priority - EV_MINPRI) +#endif + +#define EMPTY /* required for microsofts broken pseudo-c compiler */ +#define EMPTY2(a,b) /* used to suppress some warnings */ + +typedef ev_watcher *W; +typedef ev_watcher_list *WL; +typedef ev_watcher_time *WT; + +#define ev_active(w) ((W)(w))->active +#define ev_at(w) ((WT)(w))->at + +#if EV_USE_REALTIME +/* sig_atomic_t is used to avoid per-thread variables or locking but still */ +/* giving it a reasonably high chance of working on typical architectures */ +static EV_ATOMIC_T have_realtime; /* did clock_gettime (CLOCK_REALTIME) work? */ +#endif + +#if EV_USE_MONOTONIC +static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */ +#endif + +#ifndef EV_FD_TO_WIN32_HANDLE +# define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd) +#endif +#ifndef EV_WIN32_HANDLE_TO_FD +# define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0) +#endif +#ifndef EV_WIN32_CLOSE_FD +# define EV_WIN32_CLOSE_FD(fd) close (fd) +#endif + +#ifdef _WIN32 +# include "ev_win32.c" +#endif + +/*****************************************************************************/ + +#ifdef __linux +# include +#endif + +static unsigned int noinline +ev_linux_version (void) +{ +#ifdef __linux + unsigned int v = 0; + struct utsname buf; + int i; + char *p = buf.release; + + if (uname (&buf)) + return 0; + + for (i = 3+1; --i; ) + { + unsigned int c = 0; + + for (;;) + { + if (*p >= '0' && *p <= '9') + c = c * 10 + *p++ - '0'; + else + { + p += *p == '.'; + break; + } + } + + v = (v << 8) | c; + } + + return v; +#else + return 0; +#endif +} + +/*****************************************************************************/ + +#if EV_AVOID_STDIO +static void noinline +ev_printerr (const char *msg) +{ + write (STDERR_FILENO, msg, strlen (msg)); +} +#endif + +static void (*syserr_cb)(const char *msg); + +void +ev_set_syserr_cb (void (*cb)(const char *msg)) +{ + syserr_cb = cb; +} + +static void noinline +ev_syserr (const char *msg) +{ + if (!msg) + msg = "(libev) system error"; + + if (syserr_cb) + syserr_cb (msg); + else + { +#if EV_AVOID_STDIO + ev_printerr (msg); + ev_printerr (": "); + ev_printerr (strerror (errno)); + ev_printerr ("\n"); +#else + perror (msg); +#endif + abort (); + } +} + +static void * +ev_realloc_emul (void *ptr, long size) +{ +#if __GLIBC__ + return realloc (ptr, size); +#else + /* some systems, notably openbsd and darwin, fail to properly + * implement realloc (x, 0) (as required by both ansi c-89 and + * the single unix specification, so work around them here. + */ + + if (size) + return realloc (ptr, size); + + free (ptr); + return 0; +#endif +} + +static void *(*alloc)(void *ptr, long size) = ev_realloc_emul; + +void +ev_set_allocator (void *(*cb)(void *ptr, long size)) +{ + alloc = cb; +} + +inline_speed void * +ev_realloc (void *ptr, long size) +{ + ptr = alloc (ptr, size); + + if (!ptr && size) + { +#if EV_AVOID_STDIO + ev_printerr ("(libev) memory allocation failed, aborting.\n"); +#else + fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size); +#endif + abort (); + } + + return ptr; +} + +#define ev_malloc(size) ev_realloc (0, (size)) +#define ev_free(ptr) ev_realloc ((ptr), 0) + +/*****************************************************************************/ + +/* set in reify when reification needed */ +#define EV_ANFD_REIFY 1 + +/* file descriptor info structure */ +typedef struct +{ + WL head; + unsigned char events; /* the events watched for */ + unsigned char reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) */ + unsigned char emask; /* the epoll backend stores the actual kernel mask in here */ + unsigned char unused; +#if EV_USE_EPOLL + unsigned int egen; /* generation counter to counter epoll bugs */ +#endif +#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP + SOCKET handle; +#endif +#if EV_USE_IOCP + OVERLAPPED or, ow; +#endif +} ANFD; + +/* stores the pending event set for a given watcher */ +typedef struct +{ + W w; + int events; /* the pending event set for the given watcher */ +} ANPENDING; + +#if EV_USE_INOTIFY +/* hash table entry per inotify-id */ +typedef struct +{ + WL head; +} ANFS; +#endif + +/* Heap Entry */ +#if EV_HEAP_CACHE_AT + /* a heap element */ + typedef struct { + ev_tstamp at; + WT w; + } ANHE; + + #define ANHE_w(he) (he).w /* access watcher, read-write */ + #define ANHE_at(he) (he).at /* access cached at, read-only */ + #define ANHE_at_cache(he) (he).at = (he).w->at /* update at from watcher */ +#else + /* a heap element */ + typedef WT ANHE; + + #define ANHE_w(he) (he) + #define ANHE_at(he) (he)->at + #define ANHE_at_cache(he) +#endif + +#if EV_MULTIPLICITY + + struct ev_loop + { + ev_tstamp ev_rt_now; + #define ev_rt_now ((loop)->ev_rt_now) + #define VAR(name,decl) decl; + #include "ev_vars.h" + #undef VAR + }; + #include "ev_wrap.h" + + static struct ev_loop default_loop_struct; + struct ev_loop *ev_default_loop_ptr; + +#else + + ev_tstamp ev_rt_now; + #define VAR(name,decl) static decl; + #include "ev_vars.h" + #undef VAR + + static int ev_default_loop_ptr; + +#endif + +#if EV_FEATURE_API +# define EV_RELEASE_CB if (expect_false (release_cb)) release_cb (EV_A) +# define EV_ACQUIRE_CB if (expect_false (acquire_cb)) acquire_cb (EV_A) +# define EV_INVOKE_PENDING invoke_cb (EV_A) +#else +# define EV_RELEASE_CB (void)0 +# define EV_ACQUIRE_CB (void)0 +# define EV_INVOKE_PENDING ev_invoke_pending (EV_A) +#endif + +#define EVBREAK_RECURSE 0x80 + +/*****************************************************************************/ + +#ifndef EV_HAVE_EV_TIME +ev_tstamp +ev_time (void) +{ +#if EV_USE_REALTIME + if (expect_true (have_realtime)) + { + struct timespec ts; + clock_gettime (CLOCK_REALTIME, &ts); + return ts.tv_sec + ts.tv_nsec * 1e-9; + } +#endif + + struct timeval tv; + gettimeofday (&tv, 0); + return tv.tv_sec + tv.tv_usec * 1e-6; +} +#endif + +inline_size ev_tstamp +get_clock (void) +{ +#if EV_USE_MONOTONIC + if (expect_true (have_monotonic)) + { + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + return ts.tv_sec + ts.tv_nsec * 1e-9; + } +#endif + + return ev_time (); +} + +#if EV_MULTIPLICITY +ev_tstamp +ev_now (EV_P) +{ + return ev_rt_now; +} +#endif + +void +ev_sleep (ev_tstamp delay) +{ + if (delay > 0.) + { +#if EV_USE_NANOSLEEP + struct timespec ts; + + EV_TS_SET (ts, delay); + nanosleep (&ts, 0); +#elif defined(_WIN32) + Sleep ((unsigned long)(delay * 1e3)); +#else + struct timeval tv; + + /* here we rely on sys/time.h + sys/types.h + unistd.h providing select */ + /* something not guaranteed by newer posix versions, but guaranteed */ + /* by older ones */ + EV_TV_SET (tv, delay); + select (0, 0, 0, 0, &tv); +#endif + } +} + +inline_speed int +ev_timeout_to_ms (ev_tstamp timeout) +{ + int ms = timeout * 1000. + .999999; + + return expect_true (ms) ? ms : timeout < 1e-6 ? 0 : 1; +} + +/*****************************************************************************/ + +#define MALLOC_ROUND 4096 /* prefer to allocate in chunks of this size, must be 2**n and >> 4 longs */ + +/* find a suitable new size for the given array, */ +/* hopefully by rounding to a nice-to-malloc size */ +inline_size int +array_nextsize (int elem, int cur, int cnt) +{ + int ncur = cur + 1; + + do + ncur <<= 1; + while (cnt > ncur); + + /* if size is large, round to MALLOC_ROUND - 4 * longs to accomodate malloc overhead */ + if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4) + { + ncur *= elem; + ncur = (ncur + elem + (MALLOC_ROUND - 1) + sizeof (void *) * 4) & ~(MALLOC_ROUND - 1); + ncur = ncur - sizeof (void *) * 4; + ncur /= elem; + } + + return ncur; +} + +static noinline void * +array_realloc (int elem, void *base, int *cur, int cnt) +{ + *cur = array_nextsize (elem, *cur, cnt); + return ev_realloc (base, elem * *cur); +} + +#define array_init_zero(base,count) \ + memset ((void *)(base), 0, sizeof (*(base)) * (count)) + +#define array_needsize(type,base,cur,cnt,init) \ + if (expect_false ((cnt) > (cur))) \ + { \ + int ocur_ = (cur); \ + (base) = (type *)array_realloc \ + (sizeof (type), (base), &(cur), (cnt)); \ + init ((base) + (ocur_), (cur) - ocur_); \ + } + +#if 0 +#define array_slim(type,stem) \ + if (stem ## max < array_roundsize (stem ## cnt >> 2)) \ + { \ + stem ## max = array_roundsize (stem ## cnt >> 1); \ + base = (type *)ev_realloc (base, sizeof (type) * (stem ## max));\ + fprintf (stderr, "slimmed down " # stem " to %d\n", stem ## max);/*D*/\ + } +#endif + +#define array_free(stem, idx) \ + ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0; stem ## s idx = 0 + +/*****************************************************************************/ + +/* dummy callback for pending events */ +static void noinline +pendingcb (EV_P_ ev_prepare *w, int revents) +{ +} + +void noinline +ev_feed_event (EV_P_ void *w, int revents) +{ + W w_ = (W)w; + int pri = ABSPRI (w_); + + if (expect_false (w_->pending)) + pendings [pri][w_->pending - 1].events |= revents; + else + { + w_->pending = ++pendingcnt [pri]; + array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2); + pendings [pri][w_->pending - 1].w = w_; + pendings [pri][w_->pending - 1].events = revents; + } +} + +inline_speed void +feed_reverse (EV_P_ W w) +{ + array_needsize (W, rfeeds, rfeedmax, rfeedcnt + 1, EMPTY2); + rfeeds [rfeedcnt++] = w; +} + +inline_size void +feed_reverse_done (EV_P_ int revents) +{ + do + ev_feed_event (EV_A_ rfeeds [--rfeedcnt], revents); + while (rfeedcnt); +} + +inline_speed void +queue_events (EV_P_ W *events, int eventcnt, int type) +{ + int i; + + for (i = 0; i < eventcnt; ++i) + ev_feed_event (EV_A_ events [i], type); +} + +/*****************************************************************************/ + +inline_speed void +fd_event_nocheck (EV_P_ int fd, int revents) +{ + ANFD *anfd = anfds + fd; + ev_io *w; + + for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next) + { + int ev = w->events & revents; + + if (ev) + ev_feed_event (EV_A_ (W)w, ev); + } +} + +/* do not submit kernel events for fds that have reify set */ +/* because that means they changed while we were polling for new events */ +inline_speed void +fd_event (EV_P_ int fd, int revents) +{ + ANFD *anfd = anfds + fd; + + if (expect_true (!anfd->reify)) + fd_event_nocheck (EV_A_ fd, revents); +} + +void +ev_feed_fd_event (EV_P_ int fd, int revents) +{ + if (fd >= 0 && fd < anfdmax) + fd_event_nocheck (EV_A_ fd, revents); +} + +/* make sure the external fd watch events are in-sync */ +/* with the kernel/libev internal state */ +inline_size void +fd_reify (EV_P) +{ + int i; + +#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP + for (i = 0; i < fdchangecnt; ++i) + { + int fd = fdchanges [i]; + ANFD *anfd = anfds + fd; + + if (anfd->reify & EV__IOFDSET) + { + SOCKET handle = EV_FD_TO_WIN32_HANDLE (fd); + + if (handle != anfd->handle) + { + unsigned long arg; + + assert (("libev: only socket fds supported in this configuration", ioctlsocket (handle, FIONREAD, &arg) == 0)); + + /* handle changed, but fd didn't - we need to do it in two steps */ + backend_modify (EV_A_ fd, anfd->events, 0); + anfd->events = 0; + anfd->handle = handle; + } + } + } +#endif + + for (i = 0; i < fdchangecnt; ++i) + { + int fd = fdchanges [i]; + ANFD *anfd = anfds + fd; + ev_io *w; + + unsigned char o_events = anfd->events; + unsigned char o_reify = anfd->reify; + + anfd->reify = 0; + + /*if (expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */ + { + anfd->events = 0; + + for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next) + anfd->events |= (unsigned char)w->events; + + if (o_events != anfd->events) + o_reify = EV__IOFDSET; /* actually |= */ + } + + if (o_reify & EV__IOFDSET) + backend_modify (EV_A_ fd, o_events, anfd->events); + } + + fdchangecnt = 0; +} + +/* something about the given fd changed */ +inline_size void +fd_change (EV_P_ int fd, int flags) +{ + unsigned char reify = anfds [fd].reify; + anfds [fd].reify |= flags; + + if (expect_true (!reify)) + { + ++fdchangecnt; + array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2); + fdchanges [fdchangecnt - 1] = fd; + } +} + +/* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */ +inline_speed void +fd_kill (EV_P_ int fd) +{ + ev_io *w; + + while ((w = (ev_io *)anfds [fd].head)) + { + ev_io_stop (EV_A_ w); + ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE); + } +} + +/* check whether the given fd is actually valid, for error recovery */ +inline_size int +fd_valid (int fd) +{ +#ifdef _WIN32 + return EV_FD_TO_WIN32_HANDLE (fd) != -1; +#else + return fcntl (fd, F_GETFD) != -1; +#endif +} + +/* called on EBADF to verify fds */ +static void noinline +fd_ebadf (EV_P) +{ + int fd; + + for (fd = 0; fd < anfdmax; ++fd) + if (anfds [fd].events) + if (!fd_valid (fd) && errno == EBADF) + fd_kill (EV_A_ fd); +} + +/* called on ENOMEM in select/poll to kill some fds and retry */ +static void noinline +fd_enomem (EV_P) +{ + int fd; + + for (fd = anfdmax; fd--; ) + if (anfds [fd].events) + { + fd_kill (EV_A_ fd); + break; + } +} + +/* usually called after fork if backend needs to re-arm all fds from scratch */ +static void noinline +fd_rearm_all (EV_P) +{ + int fd; + + for (fd = 0; fd < anfdmax; ++fd) + if (anfds [fd].events) + { + anfds [fd].events = 0; + anfds [fd].emask = 0; + fd_change (EV_A_ fd, EV__IOFDSET | EV_ANFD_REIFY); + } +} + +/* used to prepare libev internal fd's */ +/* this is not fork-safe */ +inline_speed void +fd_intern (int fd) +{ +#ifdef _WIN32 + unsigned long arg = 1; + ioctlsocket (EV_FD_TO_WIN32_HANDLE (fd), FIONBIO, &arg); +#else + fcntl (fd, F_SETFD, FD_CLOEXEC); + fcntl (fd, F_SETFL, O_NONBLOCK); +#endif +} + +/*****************************************************************************/ + +/* + * the heap functions want a real array index. array index 0 is guaranteed to not + * be in-use at any time. the first heap entry is at array [HEAP0]. DHEAP gives + * the branching factor of the d-tree. + */ + +/* + * at the moment we allow libev the luxury of two heaps, + * a small-code-size 2-heap one and a ~1.5kb larger 4-heap + * which is more cache-efficient. + * the difference is about 5% with 50000+ watchers. + */ +#if EV_USE_4HEAP + +#define DHEAP 4 +#define HEAP0 (DHEAP - 1) /* index of first element in heap */ +#define HPARENT(k) ((((k) - HEAP0 - 1) / DHEAP) + HEAP0) +#define UPHEAP_DONE(p,k) ((p) == (k)) + +/* away from the root */ +inline_speed void +downheap (ANHE *heap, int N, int k) +{ + ANHE he = heap [k]; + ANHE *E = heap + N + HEAP0; + + for (;;) + { + ev_tstamp minat; + ANHE *minpos; + ANHE *pos = heap + DHEAP * (k - HEAP0) + HEAP0 + 1; + + /* find minimum child */ + if (expect_true (pos + DHEAP - 1 < E)) + { + /* fast path */ (minpos = pos + 0), (minat = ANHE_at (*minpos)); + if ( ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos)); + if ( ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos)); + if ( ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos)); + } + else if (pos < E) + { + /* slow path */ (minpos = pos + 0), (minat = ANHE_at (*minpos)); + if (pos + 1 < E && ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos)); + if (pos + 2 < E && ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos)); + if (pos + 3 < E && ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos)); + } + else + break; + + if (ANHE_at (he) <= minat) + break; + + heap [k] = *minpos; + ev_active (ANHE_w (*minpos)) = k; + + k = minpos - heap; + } + + heap [k] = he; + ev_active (ANHE_w (he)) = k; +} + +#else /* 4HEAP */ + +#define HEAP0 1 +#define HPARENT(k) ((k) >> 1) +#define UPHEAP_DONE(p,k) (!(p)) + +/* away from the root */ +inline_speed void +downheap (ANHE *heap, int N, int k) +{ + ANHE he = heap [k]; + + for (;;) + { + int c = k << 1; + + if (c >= N + HEAP0) + break; + + c += c + 1 < N + HEAP0 && ANHE_at (heap [c]) > ANHE_at (heap [c + 1]) + ? 1 : 0; + + if (ANHE_at (he) <= ANHE_at (heap [c])) + break; + + heap [k] = heap [c]; + ev_active (ANHE_w (heap [k])) = k; + + k = c; + } + + heap [k] = he; + ev_active (ANHE_w (he)) = k; +} +#endif + +/* towards the root */ +inline_speed void +upheap (ANHE *heap, int k) +{ + ANHE he = heap [k]; + + for (;;) + { + int p = HPARENT (k); + + if (UPHEAP_DONE (p, k) || ANHE_at (heap [p]) <= ANHE_at (he)) + break; + + heap [k] = heap [p]; + ev_active (ANHE_w (heap [k])) = k; + k = p; + } + + heap [k] = he; + ev_active (ANHE_w (he)) = k; +} + +/* move an element suitably so it is in a correct place */ +inline_size void +adjustheap (ANHE *heap, int N, int k) +{ + if (k > HEAP0 && ANHE_at (heap [k]) <= ANHE_at (heap [HPARENT (k)])) + upheap (heap, k); + else + downheap (heap, N, k); +} + +/* rebuild the heap: this function is used only once and executed rarely */ +inline_size void +reheap (ANHE *heap, int N) +{ + int i; + + /* we don't use floyds algorithm, upheap is simpler and is more cache-efficient */ + /* also, this is easy to implement and correct for both 2-heaps and 4-heaps */ + for (i = 0; i < N; ++i) + upheap (heap, i + HEAP0); +} + +/*****************************************************************************/ + +/* associate signal watchers to a signal signal */ +typedef struct +{ + EV_ATOMIC_T pending; +#if EV_MULTIPLICITY + EV_P; +#endif + WL head; +} ANSIG; + +static ANSIG signals [EV_NSIG - 1]; + +/*****************************************************************************/ + +#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE + +static void noinline +evpipe_init (EV_P) +{ + if (!ev_is_active (&pipe_w)) + { +# if EV_USE_EVENTFD + evfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evfd < 0 && errno == EINVAL) + evfd = eventfd (0, 0); + + if (evfd >= 0) + { + evpipe [0] = -1; + fd_intern (evfd); /* doing it twice doesn't hurt */ + ev_io_set (&pipe_w, evfd, EV_READ); + } + else +# endif + { + while (pipe (evpipe)) + ev_syserr ("(libev) error creating signal/async pipe"); + + fd_intern (evpipe [0]); + fd_intern (evpipe [1]); + ev_io_set (&pipe_w, evpipe [0], EV_READ); + } + + ev_io_start (EV_A_ &pipe_w); + ev_unref (EV_A); /* watcher should not keep loop alive */ + } +} + +inline_size void +evpipe_write (EV_P_ EV_ATOMIC_T *flag) +{ + if (!*flag) + { + int old_errno = errno; /* save errno because write might clobber it */ + char dummy; + + *flag = 1; + +#if EV_USE_EVENTFD + if (evfd >= 0) + { + uint64_t counter = 1; + write (evfd, &counter, sizeof (uint64_t)); + } + else +#endif + /* win32 people keep sending patches that change this write() to send() */ + /* and then run away. but send() is wrong, it wants a socket handle on win32 */ + /* so when you think this write should be a send instead, please find out */ + /* where your send() is from - it's definitely not the microsoft send, and */ + /* tell me. thank you. */ + write (evpipe [1], &dummy, 1); + + errno = old_errno; + } +} + +/* called whenever the libev signal pipe */ +/* got some events (signal, async) */ +static void +pipecb (EV_P_ ev_io *iow, int revents) +{ + int i; + +#if EV_USE_EVENTFD + if (evfd >= 0) + { + uint64_t counter; + read (evfd, &counter, sizeof (uint64_t)); + } + else +#endif + { + char dummy; + /* see discussion in evpipe_write when you think this read should be recv in win32 */ + read (evpipe [0], &dummy, 1); + } + +#if EV_SIGNAL_ENABLE + if (sig_pending) + { + sig_pending = 0; + + for (i = EV_NSIG - 1; i--; ) + if (expect_false (signals [i].pending)) + ev_feed_signal_event (EV_A_ i + 1); + } +#endif + +#if EV_ASYNC_ENABLE + if (async_pending) + { + async_pending = 0; + + for (i = asynccnt; i--; ) + if (asyncs [i]->sent) + { + asyncs [i]->sent = 0; + ev_feed_event (EV_A_ asyncs [i], EV_ASYNC); + } + } +#endif +} + +/*****************************************************************************/ + +void +ev_feed_signal (int signum) +{ +#if EV_MULTIPLICITY + EV_P = signals [signum - 1].loop; + + if (!EV_A) + return; +#endif + + signals [signum - 1].pending = 1; + evpipe_write (EV_A_ &sig_pending); +} + +static void +ev_sighandler (int signum) +{ +#ifdef _WIN32 + signal (signum, ev_sighandler); +#endif + + ev_feed_signal (signum); +} + +void noinline +ev_feed_signal_event (EV_P_ int signum) +{ + WL w; + + if (expect_false (signum <= 0 || signum > EV_NSIG)) + return; + + --signum; + +#if EV_MULTIPLICITY + /* it is permissible to try to feed a signal to the wrong loop */ + /* or, likely more useful, feeding a signal nobody is waiting for */ + + if (expect_false (signals [signum].loop != EV_A)) + return; +#endif + + signals [signum].pending = 0; + + for (w = signals [signum].head; w; w = w->next) + ev_feed_event (EV_A_ (W)w, EV_SIGNAL); +} + +#if EV_USE_SIGNALFD +static void +sigfdcb (EV_P_ ev_io *iow, int revents) +{ + struct signalfd_siginfo si[2], *sip; /* these structs are big */ + + for (;;) + { + ssize_t res = read (sigfd, si, sizeof (si)); + + /* not ISO-C, as res might be -1, but works with SuS */ + for (sip = si; (char *)sip < (char *)si + res; ++sip) + ev_feed_signal_event (EV_A_ sip->ssi_signo); + + if (res < (ssize_t)sizeof (si)) + break; + } +} +#endif + +#endif + +/*****************************************************************************/ + +#if EV_CHILD_ENABLE +static WL childs [EV_PID_HASHSIZE]; + +static ev_signal childev; + +#ifndef WIFCONTINUED +# define WIFCONTINUED(status) 0 +#endif + +/* handle a single child status event */ +inline_speed void +child_reap (EV_P_ int chain, int pid, int status) +{ + ev_child *w; + int traced = WIFSTOPPED (status) || WIFCONTINUED (status); + + for (w = (ev_child *)childs [chain & ((EV_PID_HASHSIZE) - 1)]; w; w = (ev_child *)((WL)w)->next) + { + if ((w->pid == pid || !w->pid) + && (!traced || (w->flags & 1))) + { + ev_set_priority (w, EV_MAXPRI); /* need to do it *now*, this *must* be the same prio as the signal watcher itself */ + w->rpid = pid; + w->rstatus = status; + ev_feed_event (EV_A_ (W)w, EV_CHILD); + } + } +} + +#ifndef WCONTINUED +# define WCONTINUED 0 +#endif + +/* called on sigchld etc., calls waitpid */ +static void +childcb (EV_P_ ev_signal *sw, int revents) +{ + int pid, status; + + /* some systems define WCONTINUED but then fail to support it (linux 2.4) */ + if (0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED))) + if (!WCONTINUED + || errno != EINVAL + || 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED))) + return; + + /* make sure we are called again until all children have been reaped */ + /* we need to do it this way so that the callback gets called before we continue */ + ev_feed_event (EV_A_ (W)sw, EV_SIGNAL); + + child_reap (EV_A_ pid, pid, status); + if ((EV_PID_HASHSIZE) > 1) + child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */ +} + +#endif + +/*****************************************************************************/ + +#if EV_USE_IOCP +# include "ev_iocp.c" +#endif +#if EV_USE_PORT +# include "ev_port.c" +#endif +#if EV_USE_KQUEUE +# include "ev_kqueue.c" +#endif +#if EV_USE_EPOLL +# include "ev_epoll.c" +#endif +#if EV_USE_POLL +# include "ev_poll.c" +#endif +#if EV_USE_SELECT +# include "ev_select.c" +#endif + +int +ev_version_major (void) +{ + return EV_VERSION_MAJOR; +} + +int +ev_version_minor (void) +{ + return EV_VERSION_MINOR; +} + +/* return true if we are running with elevated privileges and should ignore env variables */ +int inline_size +enable_secure (void) +{ +#ifdef _WIN32 + return 0; +#else + return getuid () != geteuid () + || getgid () != getegid (); +#endif +} + +unsigned int +ev_supported_backends (void) +{ + unsigned int flags = 0; + + if (EV_USE_PORT ) flags |= EVBACKEND_PORT; + if (EV_USE_KQUEUE) flags |= EVBACKEND_KQUEUE; + if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL; + if (EV_USE_POLL ) flags |= EVBACKEND_POLL; + if (EV_USE_SELECT) flags |= EVBACKEND_SELECT; + + return flags; +} + +unsigned int +ev_recommended_backends (void) +{ + unsigned int flags = ev_supported_backends (); + +#ifndef __NetBSD__ + /* kqueue is borked on everything but netbsd apparently */ + /* it usually doesn't work correctly on anything but sockets and pipes */ + flags &= ~EVBACKEND_KQUEUE; +#endif +#ifdef __APPLE__ + /* only select works correctly on that "unix-certified" platform */ + flags &= ~EVBACKEND_KQUEUE; /* horribly broken, even for sockets */ + flags &= ~EVBACKEND_POLL; /* poll is based on kqueue from 10.5 onwards */ +#endif +#ifdef __FreeBSD__ + flags &= ~EVBACKEND_POLL; /* poll return value is unusable (http://forums.freebsd.org/archive/index.php/t-10270.html) */ +#endif + + return flags; +} + +unsigned int +ev_embeddable_backends (void) +{ + int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT; + + /* epoll embeddability broken on all linux versions up to at least 2.6.23 */ + if (ev_linux_version () < 0x020620) /* disable it on linux < 2.6.32 */ + flags &= ~EVBACKEND_EPOLL; + + return flags; +} + +unsigned int +ev_backend (EV_P) +{ + return backend; +} + +#if EV_FEATURE_API +unsigned int +ev_iteration (EV_P) +{ + return loop_count; +} + +unsigned int +ev_depth (EV_P) +{ + return loop_depth; +} + +void +ev_set_io_collect_interval (EV_P_ ev_tstamp interval) +{ + io_blocktime = interval; +} + +void +ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) +{ + timeout_blocktime = interval; +} + +void +ev_set_userdata (EV_P_ void *data) +{ + userdata = data; +} + +void * +ev_userdata (EV_P) +{ + return userdata; +} + +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)) +{ + invoke_cb = invoke_pending_cb; +} + +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)) +{ + release_cb = release; + acquire_cb = acquire; +} +#endif + +/* initialise a loop structure, must be zero-initialised */ +static void noinline +loop_init (EV_P_ unsigned int flags) +{ + if (!backend) + { + origflags = flags; + +#if EV_USE_REALTIME + if (!have_realtime) + { + struct timespec ts; + + if (!clock_gettime (CLOCK_REALTIME, &ts)) + have_realtime = 1; + } +#endif + +#if EV_USE_MONOTONIC + if (!have_monotonic) + { + struct timespec ts; + + if (!clock_gettime (CLOCK_MONOTONIC, &ts)) + have_monotonic = 1; + } +#endif + + /* pid check not overridable via env */ +#ifndef _WIN32 + if (flags & EVFLAG_FORKCHECK) + curpid = getpid (); +#endif + + if (!(flags & EVFLAG_NOENV) + && !enable_secure () + && getenv ("LIBEV_FLAGS")) + flags = atoi (getenv ("LIBEV_FLAGS")); + + ev_rt_now = ev_time (); + mn_now = get_clock (); + now_floor = mn_now; + rtmn_diff = ev_rt_now - mn_now; +#if EV_FEATURE_API + invoke_cb = ev_invoke_pending; +#endif + + io_blocktime = 0.; + timeout_blocktime = 0.; + backend = 0; + backend_fd = -1; + sig_pending = 0; +#if EV_ASYNC_ENABLE + async_pending = 0; +#endif +#if EV_USE_INOTIFY + fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2; +#endif +#if EV_USE_SIGNALFD + sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1; +#endif + + if (!(flags & EVBACKEND_MASK)) + flags |= ev_recommended_backends (); + +#if EV_USE_IOCP + if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags); +#endif +#if EV_USE_PORT + if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags); +#endif +#if EV_USE_KQUEUE + if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags); +#endif +#if EV_USE_EPOLL + if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags); +#endif +#if EV_USE_POLL + if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags); +#endif +#if EV_USE_SELECT + if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags); +#endif + + ev_prepare_init (&pending_w, pendingcb); + +#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE + ev_init (&pipe_w, pipecb); + ev_set_priority (&pipe_w, EV_MAXPRI); +#endif + } +} + +/* free up a loop structure */ +void +ev_loop_destroy (EV_P) +{ + int i; + +#if EV_MULTIPLICITY + /* mimic free (0) */ + if (!EV_A) + return; +#endif + +#if EV_CLEANUP_ENABLE + /* queue cleanup watchers (and execute them) */ + if (expect_false (cleanupcnt)) + { + queue_events (EV_A_ (W *)cleanups, cleanupcnt, EV_CLEANUP); + EV_INVOKE_PENDING; + } +#endif + +#if EV_CHILD_ENABLE + if (ev_is_active (&childev)) + { + ev_ref (EV_A); /* child watcher */ + ev_signal_stop (EV_A_ &childev); + } +#endif + + if (ev_is_active (&pipe_w)) + { + /*ev_ref (EV_A);*/ + /*ev_io_stop (EV_A_ &pipe_w);*/ + +#if EV_USE_EVENTFD + if (evfd >= 0) + close (evfd); +#endif + + if (evpipe [0] >= 0) + { + EV_WIN32_CLOSE_FD (evpipe [0]); + EV_WIN32_CLOSE_FD (evpipe [1]); + } + } + +#if EV_USE_SIGNALFD + if (ev_is_active (&sigfd_w)) + close (sigfd); +#endif + +#if EV_USE_INOTIFY + if (fs_fd >= 0) + close (fs_fd); +#endif + + if (backend_fd >= 0) + close (backend_fd); + +#if EV_USE_IOCP + if (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A); +#endif +#if EV_USE_PORT + if (backend == EVBACKEND_PORT ) port_destroy (EV_A); +#endif +#if EV_USE_KQUEUE + if (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A); +#endif +#if EV_USE_EPOLL + if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A); +#endif +#if EV_USE_POLL + if (backend == EVBACKEND_POLL ) poll_destroy (EV_A); +#endif +#if EV_USE_SELECT + if (backend == EVBACKEND_SELECT) select_destroy (EV_A); +#endif + + for (i = NUMPRI; i--; ) + { + array_free (pending, [i]); +#if EV_IDLE_ENABLE + array_free (idle, [i]); +#endif + } + + ev_free (anfds); anfds = 0; anfdmax = 0; + + /* have to use the microsoft-never-gets-it-right macro */ + array_free (rfeed, EMPTY); + array_free (fdchange, EMPTY); + array_free (timer, EMPTY); +#if EV_PERIODIC_ENABLE + array_free (periodic, EMPTY); +#endif +#if EV_FORK_ENABLE + array_free (fork, EMPTY); +#endif +#if EV_CLEANUP_ENABLE + array_free (cleanup, EMPTY); +#endif + array_free (prepare, EMPTY); + array_free (check, EMPTY); +#if EV_ASYNC_ENABLE + array_free (async, EMPTY); +#endif + + backend = 0; + +#if EV_MULTIPLICITY + if (ev_is_default_loop (EV_A)) +#endif + ev_default_loop_ptr = 0; +#if EV_MULTIPLICITY + else + ev_free (EV_A); +#endif +} + +#if EV_USE_INOTIFY +inline_size void infy_fork (EV_P); +#endif + +inline_size void +loop_fork (EV_P) +{ +#if EV_USE_PORT + if (backend == EVBACKEND_PORT ) port_fork (EV_A); +#endif +#if EV_USE_KQUEUE + if (backend == EVBACKEND_KQUEUE) kqueue_fork (EV_A); +#endif +#if EV_USE_EPOLL + if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A); +#endif +#if EV_USE_INOTIFY + infy_fork (EV_A); +#endif + + if (ev_is_active (&pipe_w)) + { + /* this "locks" the handlers against writing to the pipe */ + /* while we modify the fd vars */ + sig_pending = 1; +#if EV_ASYNC_ENABLE + async_pending = 1; +#endif + + ev_ref (EV_A); + ev_io_stop (EV_A_ &pipe_w); + +#if EV_USE_EVENTFD + if (evfd >= 0) + close (evfd); +#endif + + if (evpipe [0] >= 0) + { + EV_WIN32_CLOSE_FD (evpipe [0]); + EV_WIN32_CLOSE_FD (evpipe [1]); + } + +#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE + evpipe_init (EV_A); + /* now iterate over everything, in case we missed something */ + pipecb (EV_A_ &pipe_w, EV_READ); +#endif + } + + postfork = 0; +} + +#if EV_MULTIPLICITY + +struct ev_loop * +ev_loop_new (unsigned int flags) +{ + EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop)); + + memset (EV_A, 0, sizeof (struct ev_loop)); + loop_init (EV_A_ flags); + + if (ev_backend (EV_A)) + return EV_A; + + ev_free (EV_A); + return 0; +} + +#endif /* multiplicity */ + +#if EV_VERIFY +static void noinline +verify_watcher (EV_P_ W w) +{ + assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI)); + + if (w->pending) + assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w)); +} + +static void noinline +verify_heap (EV_P_ ANHE *heap, int N) +{ + int i; + + for (i = HEAP0; i < N + HEAP0; ++i) + { + assert (("libev: active index mismatch in heap", ev_active (ANHE_w (heap [i])) == i)); + assert (("libev: heap condition violated", i == HEAP0 || ANHE_at (heap [HPARENT (i)]) <= ANHE_at (heap [i]))); + assert (("libev: heap at cache mismatch", ANHE_at (heap [i]) == ev_at (ANHE_w (heap [i])))); + + verify_watcher (EV_A_ (W)ANHE_w (heap [i])); + } +} + +static void noinline +array_verify (EV_P_ W *ws, int cnt) +{ + while (cnt--) + { + assert (("libev: active index mismatch", ev_active (ws [cnt]) == cnt + 1)); + verify_watcher (EV_A_ ws [cnt]); + } +} +#endif + +#if EV_FEATURE_API +void +ev_verify (EV_P) +{ +#if EV_VERIFY + int i; + WL w; + + assert (activecnt >= -1); + + assert (fdchangemax >= fdchangecnt); + for (i = 0; i < fdchangecnt; ++i) + assert (("libev: negative fd in fdchanges", fdchanges [i] >= 0)); + + assert (anfdmax >= 0); + for (i = 0; i < anfdmax; ++i) + for (w = anfds [i].head; w; w = w->next) + { + verify_watcher (EV_A_ (W)w); + assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1)); + assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i)); + } + + assert (timermax >= timercnt); + verify_heap (EV_A_ timers, timercnt); + +#if EV_PERIODIC_ENABLE + assert (periodicmax >= periodiccnt); + verify_heap (EV_A_ periodics, periodiccnt); +#endif + + for (i = NUMPRI; i--; ) + { + assert (pendingmax [i] >= pendingcnt [i]); +#if EV_IDLE_ENABLE + assert (idleall >= 0); + assert (idlemax [i] >= idlecnt [i]); + array_verify (EV_A_ (W *)idles [i], idlecnt [i]); +#endif + } + +#if EV_FORK_ENABLE + assert (forkmax >= forkcnt); + array_verify (EV_A_ (W *)forks, forkcnt); +#endif + +#if EV_CLEANUP_ENABLE + assert (cleanupmax >= cleanupcnt); + array_verify (EV_A_ (W *)cleanups, cleanupcnt); +#endif + +#if EV_ASYNC_ENABLE + assert (asyncmax >= asynccnt); + array_verify (EV_A_ (W *)asyncs, asynccnt); +#endif + +#if EV_PREPARE_ENABLE + assert (preparemax >= preparecnt); + array_verify (EV_A_ (W *)prepares, preparecnt); +#endif + +#if EV_CHECK_ENABLE + assert (checkmax >= checkcnt); + array_verify (EV_A_ (W *)checks, checkcnt); +#endif + +# if 0 +#if EV_CHILD_ENABLE + for (w = (ev_child *)childs [chain & ((EV_PID_HASHSIZE) - 1)]; w; w = (ev_child *)((WL)w)->next) + for (signum = EV_NSIG; signum--; ) if (signals [signum].pending) +#endif +# endif +#endif +} +#endif + +#if EV_MULTIPLICITY +struct ev_loop * +#else +int +#endif +ev_default_loop (unsigned int flags) +{ + if (!ev_default_loop_ptr) + { +#if EV_MULTIPLICITY + EV_P = ev_default_loop_ptr = &default_loop_struct; +#else + ev_default_loop_ptr = 1; +#endif + + loop_init (EV_A_ flags); + + if (ev_backend (EV_A)) + { +#if EV_CHILD_ENABLE + ev_signal_init (&childev, childcb, SIGCHLD); + ev_set_priority (&childev, EV_MAXPRI); + ev_signal_start (EV_A_ &childev); + ev_unref (EV_A); /* child watcher should not keep loop alive */ +#endif + } + else + ev_default_loop_ptr = 0; + } + + return ev_default_loop_ptr; +} + +void +ev_loop_fork (EV_P) +{ + postfork = 1; /* must be in line with ev_default_fork */ +} + +/*****************************************************************************/ + +void +ev_invoke (EV_P_ void *w, int revents) +{ + EV_CB_INVOKE ((W)w, revents); +} + +unsigned int +ev_pending_count (EV_P) +{ + int pri; + unsigned int count = 0; + + for (pri = NUMPRI; pri--; ) + count += pendingcnt [pri]; + + return count; +} + +void noinline +ev_invoke_pending (EV_P) +{ + int pri; + + for (pri = NUMPRI; pri--; ) + while (pendingcnt [pri]) + { + ANPENDING *p = pendings [pri] + --pendingcnt [pri]; + + p->w->pending = 0; + EV_CB_INVOKE (p->w, p->events); + EV_FREQUENT_CHECK; + } +} + +#if EV_IDLE_ENABLE +/* make idle watchers pending. this handles the "call-idle */ +/* only when higher priorities are idle" logic */ +inline_size void +idle_reify (EV_P) +{ + if (expect_false (idleall)) + { + int pri; + + for (pri = NUMPRI; pri--; ) + { + if (pendingcnt [pri]) + break; + + if (idlecnt [pri]) + { + queue_events (EV_A_ (W *)idles [pri], idlecnt [pri], EV_IDLE); + break; + } + } + } +} +#endif + +/* make timers pending */ +inline_size void +timers_reify (EV_P) +{ + EV_FREQUENT_CHECK; + + if (timercnt && ANHE_at (timers [HEAP0]) < mn_now) + { + do + { + ev_timer *w = (ev_timer *)ANHE_w (timers [HEAP0]); + + /*assert (("libev: inactive timer on timer heap detected", ev_is_active (w)));*/ + + /* first reschedule or stop timer */ + if (w->repeat) + { + ev_at (w) += w->repeat; + if (ev_at (w) < mn_now) + ev_at (w) = mn_now; + + assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > 0.)); + + ANHE_at_cache (timers [HEAP0]); + downheap (timers, timercnt, HEAP0); + } + else + ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer */ + + EV_FREQUENT_CHECK; + feed_reverse (EV_A_ (W)w); + } + while (timercnt && ANHE_at (timers [HEAP0]) < mn_now); + + feed_reverse_done (EV_A_ EV_TIMER); + } +} + +#if EV_PERIODIC_ENABLE + +inline_speed void +periodic_recalc (EV_P_ ev_periodic *w) +{ + /* TODO: use slow but potentially more correct incremental algo, */ + /* also do not rely on ceil */ + ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval; +} + +/* make periodics pending */ +inline_size void +periodics_reify (EV_P) +{ + EV_FREQUENT_CHECK; + + while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now) + { + int feed_count = 0; + + do + { + ev_periodic *w = (ev_periodic *)ANHE_w (periodics [HEAP0]); + + /*assert (("libev: inactive timer on periodic heap detected", ev_is_active (w)));*/ + + /* first reschedule or stop timer */ + if (w->reschedule_cb) + { + ev_at (w) = w->reschedule_cb (w, ev_rt_now); + + assert (("libev: ev_periodic reschedule callback returned time in the past", ev_at (w) >= ev_rt_now)); + + ANHE_at_cache (periodics [HEAP0]); + downheap (periodics, periodiccnt, HEAP0); + } + else if (w->interval) + { + periodic_recalc (EV_A_ w); + + /* if next trigger time is not sufficiently in the future, put it there */ + /* this might happen because of floating point inexactness */ + if (ev_at (w) - ev_rt_now < TIME_EPSILON) + { + ev_at (w) += w->interval; + + /* if interval is unreasonably low we might still have a time in the past */ + /* so correct this. this will make the periodic very inexact, but the user */ + /* has effectively asked to get triggered more often than possible */ + if (ev_at (w) < ev_rt_now) + ev_at (w) = ev_rt_now; + } + + ANHE_at_cache (periodics [HEAP0]); + downheap (periodics, periodiccnt, HEAP0); + } + else + ev_periodic_stop (EV_A_ w); /* nonrepeating: stop timer */ + + EV_FREQUENT_CHECK; + feed_reverse (EV_A_ (W)w); + } + while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now); + + feed_reverse_done (EV_A_ EV_PERIODIC); + } +} + +/* simply recalculate all periodics */ +/* TODO: maybe ensure that at least one event happens when jumping forward? */ +static void noinline +periodics_reschedule (EV_P) +{ + int i; + + /* adjust periodics after time jump */ + for (i = HEAP0; i < periodiccnt + HEAP0; ++i) + { + ev_periodic *w = (ev_periodic *)ANHE_w (periodics [i]); + + if (w->reschedule_cb) + ev_at (w) = w->reschedule_cb (w, ev_rt_now); + else if (w->interval) + periodic_recalc (EV_A_ w); + + ANHE_at_cache (periodics [i]); + } + + reheap (periodics, periodiccnt); +} +#endif + +/* adjust all timers by a given offset */ +static void noinline +timers_reschedule (EV_P_ ev_tstamp adjust) +{ + int i; + + for (i = 0; i < timercnt; ++i) + { + ANHE *he = timers + i + HEAP0; + ANHE_w (*he)->at += adjust; + ANHE_at_cache (*he); + } +} + +/* fetch new monotonic and realtime times from the kernel */ +/* also detect if there was a timejump, and act accordingly */ +inline_speed void +time_update (EV_P_ ev_tstamp max_block) +{ +#if EV_USE_MONOTONIC + if (expect_true (have_monotonic)) + { + int i; + ev_tstamp odiff = rtmn_diff; + + mn_now = get_clock (); + + /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */ + /* interpolate in the meantime */ + if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5)) + { + ev_rt_now = rtmn_diff + mn_now; + return; + } + + now_floor = mn_now; + ev_rt_now = ev_time (); + + /* loop a few times, before making important decisions. + * on the choice of "4": one iteration isn't enough, + * in case we get preempted during the calls to + * ev_time and get_clock. a second call is almost guaranteed + * to succeed in that case, though. and looping a few more times + * doesn't hurt either as we only do this on time-jumps or + * in the unlikely event of having been preempted here. + */ + for (i = 4; --i; ) + { + rtmn_diff = ev_rt_now - mn_now; + + if (expect_true (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP)) + return; /* all is well */ + + ev_rt_now = ev_time (); + mn_now = get_clock (); + now_floor = mn_now; + } + + /* no timer adjustment, as the monotonic clock doesn't jump */ + /* timers_reschedule (EV_A_ rtmn_diff - odiff) */ +# if EV_PERIODIC_ENABLE + periodics_reschedule (EV_A); +# endif + } + else +#endif + { + ev_rt_now = ev_time (); + + if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP)) + { + /* adjust timers. this is easy, as the offset is the same for all of them */ + timers_reschedule (EV_A_ ev_rt_now - mn_now); +#if EV_PERIODIC_ENABLE + periodics_reschedule (EV_A); +#endif + } + + mn_now = ev_rt_now; + } +} + +void +ev_run (EV_P_ int flags) +{ +#if EV_FEATURE_API + ++loop_depth; +#endif + + assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE)); + + loop_done = EVBREAK_CANCEL; + + EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ + + do + { +#if EV_VERIFY >= 2 + ev_verify (EV_A); +#endif + +#ifndef _WIN32 + if (expect_false (curpid)) /* penalise the forking check even more */ + if (expect_false (getpid () != curpid)) + { + curpid = getpid (); + postfork = 1; + } +#endif + +#if EV_FORK_ENABLE + /* we might have forked, so queue fork handlers */ + if (expect_false (postfork)) + if (forkcnt) + { + queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK); + EV_INVOKE_PENDING; + } +#endif + +#if EV_PREPARE_ENABLE + /* queue prepare watchers (and execute them) */ + if (expect_false (preparecnt)) + { + queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE); + EV_INVOKE_PENDING; + } +#endif + + if (expect_false (loop_done)) + break; + + /* we might have forked, so reify kernel state if necessary */ + if (expect_false (postfork)) + loop_fork (EV_A); + + /* update fd-related kernel structures */ + fd_reify (EV_A); + + /* calculate blocking time */ + { + ev_tstamp waittime = 0.; + ev_tstamp sleeptime = 0.; + + /* remember old timestamp for io_blocktime calculation */ + ev_tstamp prev_mn_now = mn_now; + + /* update time to cancel out callback processing overhead */ + time_update (EV_A_ 1e100); + + if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt))) + { + waittime = MAX_BLOCKTIME; + + if (timercnt) + { + ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge; + if (waittime > to) waittime = to; + } + +#if EV_PERIODIC_ENABLE + if (periodiccnt) + { + ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge; + if (waittime > to) waittime = to; + } +#endif + + /* don't let timeouts decrease the waittime below timeout_blocktime */ + if (expect_false (waittime < timeout_blocktime)) + waittime = timeout_blocktime; + + /* extra check because io_blocktime is commonly 0 */ + if (expect_false (io_blocktime)) + { + sleeptime = io_blocktime - (mn_now - prev_mn_now); + + if (sleeptime > waittime - backend_fudge) + sleeptime = waittime - backend_fudge; + + if (expect_true (sleeptime > 0.)) + { + ev_sleep (sleeptime); + waittime -= sleeptime; + } + } + } + +#if EV_FEATURE_API + ++loop_count; +#endif + assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ + backend_poll (EV_A_ waittime); + assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ + + /* update ev_rt_now, do magic */ + time_update (EV_A_ waittime + sleeptime); + } + + /* queue pending timers and reschedule them */ + timers_reify (EV_A); /* relative timers called last */ +#if EV_PERIODIC_ENABLE + periodics_reify (EV_A); /* absolute timers called first */ +#endif + +#if EV_IDLE_ENABLE + /* queue idle watchers unless other events are pending */ + idle_reify (EV_A); +#endif + +#if EV_CHECK_ENABLE + /* queue check watchers, to be executed first */ + if (expect_false (checkcnt)) + queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK); +#endif + + EV_INVOKE_PENDING; + } + while (expect_true ( + activecnt + && !loop_done + && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT)) + )); + + if (loop_done == EVBREAK_ONE) + loop_done = EVBREAK_CANCEL; + +#if EV_FEATURE_API + --loop_depth; +#endif +} + +void +ev_break (EV_P_ int how) +{ + loop_done = how; +} + +void +ev_ref (EV_P) +{ + ++activecnt; +} + +void +ev_unref (EV_P) +{ + --activecnt; +} + +void +ev_now_update (EV_P) +{ + time_update (EV_A_ 1e100); +} + +void +ev_suspend (EV_P) +{ + ev_now_update (EV_A); +} + +void +ev_resume (EV_P) +{ + ev_tstamp mn_prev = mn_now; + + ev_now_update (EV_A); + timers_reschedule (EV_A_ mn_now - mn_prev); +#if EV_PERIODIC_ENABLE + /* TODO: really do this? */ + periodics_reschedule (EV_A); +#endif +} + +/*****************************************************************************/ +/* singly-linked list management, used when the expected list length is short */ + +inline_size void +wlist_add (WL *head, WL elem) +{ + elem->next = *head; + *head = elem; +} + +inline_size void +wlist_del (WL *head, WL elem) +{ + while (*head) + { + if (expect_true (*head == elem)) + { + *head = elem->next; + break; + } + + head = &(*head)->next; + } +} + +/* internal, faster, version of ev_clear_pending */ +inline_speed void +clear_pending (EV_P_ W w) +{ + if (w->pending) + { + pendings [ABSPRI (w)][w->pending - 1].w = (W)&pending_w; + w->pending = 0; + } +} + +int +ev_clear_pending (EV_P_ void *w) +{ + W w_ = (W)w; + int pending = w_->pending; + + if (expect_true (pending)) + { + ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1; + p->w = (W)&pending_w; + w_->pending = 0; + return p->events; + } + else + return 0; +} + +inline_size void +pri_adjust (EV_P_ W w) +{ + int pri = ev_priority (w); + pri = pri < EV_MINPRI ? EV_MINPRI : pri; + pri = pri > EV_MAXPRI ? EV_MAXPRI : pri; + ev_set_priority (w, pri); +} + +inline_speed void +ev_start (EV_P_ W w, int active) +{ + pri_adjust (EV_A_ w); + w->active = active; + ev_ref (EV_A); +} + +inline_size void +ev_stop (EV_P_ W w) +{ + ev_unref (EV_A); + w->active = 0; +} + +/*****************************************************************************/ + +void noinline +ev_io_start (EV_P_ ev_io *w) +{ + int fd = w->fd; + + if (expect_false (ev_is_active (w))) + return; + + assert (("libev: ev_io_start called with negative fd", fd >= 0)); + assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE)))); + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, 1); + array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero); + wlist_add (&anfds[fd].head, (WL)w); + + fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY); + w->events &= ~EV__IOFDSET; + + EV_FREQUENT_CHECK; +} + +void noinline +ev_io_stop (EV_P_ ev_io *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + assert (("libev: ev_io_stop called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax)); + + EV_FREQUENT_CHECK; + + wlist_del (&anfds[w->fd].head, (WL)w); + ev_stop (EV_A_ (W)w); + + fd_change (EV_A_ w->fd, EV_ANFD_REIFY); + + EV_FREQUENT_CHECK; +} + +void noinline +ev_timer_start (EV_P_ ev_timer *w) +{ + if (expect_false (ev_is_active (w))) + return; + + ev_at (w) += mn_now; + + assert (("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.)); + + EV_FREQUENT_CHECK; + + ++timercnt; + ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1); + array_needsize (ANHE, timers, timermax, ev_active (w) + 1, EMPTY2); + ANHE_w (timers [ev_active (w)]) = (WT)w; + ANHE_at_cache (timers [ev_active (w)]); + upheap (timers, ev_active (w)); + + EV_FREQUENT_CHECK; + + /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/ +} + +void noinline +ev_timer_stop (EV_P_ ev_timer *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + assert (("libev: internal timer heap corruption", ANHE_w (timers [active]) == (WT)w)); + + --timercnt; + + if (expect_true (active < timercnt + HEAP0)) + { + timers [active] = timers [timercnt + HEAP0]; + adjustheap (timers, timercnt, active); + } + } + + ev_at (w) -= mn_now; + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} + +void noinline +ev_timer_again (EV_P_ ev_timer *w) +{ + EV_FREQUENT_CHECK; + + if (ev_is_active (w)) + { + if (w->repeat) + { + ev_at (w) = mn_now + w->repeat; + ANHE_at_cache (timers [ev_active (w)]); + adjustheap (timers, timercnt, ev_active (w)); + } + else + ev_timer_stop (EV_A_ w); + } + else if (w->repeat) + { + ev_at (w) = w->repeat; + ev_timer_start (EV_A_ w); + } + + EV_FREQUENT_CHECK; +} + +ev_tstamp +ev_timer_remaining (EV_P_ ev_timer *w) +{ + return ev_at (w) - (ev_is_active (w) ? mn_now : 0.); +} + +#if EV_PERIODIC_ENABLE +void noinline +ev_periodic_start (EV_P_ ev_periodic *w) +{ + if (expect_false (ev_is_active (w))) + return; + + if (w->reschedule_cb) + ev_at (w) = w->reschedule_cb (w, ev_rt_now); + else if (w->interval) + { + assert (("libev: ev_periodic_start called with negative interval value", w->interval >= 0.)); + periodic_recalc (EV_A_ w); + } + else + ev_at (w) = w->offset; + + EV_FREQUENT_CHECK; + + ++periodiccnt; + ev_start (EV_A_ (W)w, periodiccnt + HEAP0 - 1); + array_needsize (ANHE, periodics, periodicmax, ev_active (w) + 1, EMPTY2); + ANHE_w (periodics [ev_active (w)]) = (WT)w; + ANHE_at_cache (periodics [ev_active (w)]); + upheap (periodics, ev_active (w)); + + EV_FREQUENT_CHECK; + + /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/ +} + +void noinline +ev_periodic_stop (EV_P_ ev_periodic *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + assert (("libev: internal periodic heap corruption", ANHE_w (periodics [active]) == (WT)w)); + + --periodiccnt; + + if (expect_true (active < periodiccnt + HEAP0)) + { + periodics [active] = periodics [periodiccnt + HEAP0]; + adjustheap (periodics, periodiccnt, active); + } + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} + +void noinline +ev_periodic_again (EV_P_ ev_periodic *w) +{ + /* TODO: use adjustheap and recalculation */ + ev_periodic_stop (EV_A_ w); + ev_periodic_start (EV_A_ w); +} +#endif + +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +#if EV_SIGNAL_ENABLE + +void noinline +ev_signal_start (EV_P_ ev_signal *w) +{ + if (expect_false (ev_is_active (w))) + return; + + assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG)); + +#if EV_MULTIPLICITY + assert (("libev: a signal must not be attached to two different loops", + !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop)); + + signals [w->signum - 1].loop = EV_A; +#endif + + EV_FREQUENT_CHECK; + +#if EV_USE_SIGNALFD + if (sigfd == -2) + { + sigfd = signalfd (-1, &sigfd_set, SFD_NONBLOCK | SFD_CLOEXEC); + if (sigfd < 0 && errno == EINVAL) + sigfd = signalfd (-1, &sigfd_set, 0); /* retry without flags */ + + if (sigfd >= 0) + { + fd_intern (sigfd); /* doing it twice will not hurt */ + + sigemptyset (&sigfd_set); + + ev_io_init (&sigfd_w, sigfdcb, sigfd, EV_READ); + ev_set_priority (&sigfd_w, EV_MAXPRI); + ev_io_start (EV_A_ &sigfd_w); + ev_unref (EV_A); /* signalfd watcher should not keep loop alive */ + } + } + + if (sigfd >= 0) + { + /* TODO: check .head */ + sigaddset (&sigfd_set, w->signum); + sigprocmask (SIG_BLOCK, &sigfd_set, 0); + + signalfd (sigfd, &sigfd_set, 0); + } +#endif + + ev_start (EV_A_ (W)w, 1); + wlist_add (&signals [w->signum - 1].head, (WL)w); + + if (!((WL)w)->next) +# if EV_USE_SIGNALFD + if (sigfd < 0) /*TODO*/ +# endif + { +# ifdef _WIN32 + evpipe_init (EV_A); + + signal (w->signum, ev_sighandler); +# else + struct sigaction sa; + + evpipe_init (EV_A); + + sa.sa_handler = ev_sighandler; + sigfillset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */ + sigaction (w->signum, &sa, 0); + + if (origflags & EVFLAG_NOSIGMASK) + { + sigemptyset (&sa.sa_mask); + sigaddset (&sa.sa_mask, w->signum); + sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); + } +#endif + } + + EV_FREQUENT_CHECK; +} + +void noinline +ev_signal_stop (EV_P_ ev_signal *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + wlist_del (&signals [w->signum - 1].head, (WL)w); + ev_stop (EV_A_ (W)w); + + if (!signals [w->signum - 1].head) + { +#if EV_MULTIPLICITY + signals [w->signum - 1].loop = 0; /* unattach from signal */ +#endif +#if EV_USE_SIGNALFD + if (sigfd >= 0) + { + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, w->signum); + sigdelset (&sigfd_set, w->signum); + + signalfd (sigfd, &sigfd_set, 0); + sigprocmask (SIG_UNBLOCK, &ss, 0); + } + else +#endif + signal (w->signum, SIG_DFL); + } + + EV_FREQUENT_CHECK; +} + +#endif + +#if EV_CHILD_ENABLE + +void +ev_child_start (EV_P_ ev_child *w) +{ +#if EV_MULTIPLICITY + assert (("libev: child watchers are only supported in the default loop", loop == ev_default_loop_ptr)); +#endif + if (expect_false (ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, 1); + wlist_add (&childs [w->pid & ((EV_PID_HASHSIZE) - 1)], (WL)w); + + EV_FREQUENT_CHECK; +} + +void +ev_child_stop (EV_P_ ev_child *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + wlist_del (&childs [w->pid & ((EV_PID_HASHSIZE) - 1)], (WL)w); + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} + +#endif + +#if EV_STAT_ENABLE + +# ifdef _WIN32 +# undef lstat +# define lstat(a,b) _stati64 (a,b) +# endif + +#define DEF_STAT_INTERVAL 5.0074891 +#define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */ +#define MIN_STAT_INTERVAL 0.1074891 + +static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents); + +#if EV_USE_INOTIFY + +/* the * 2 is to allow for alignment padding, which for some reason is >> 8 */ +# define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX) + +static void noinline +infy_add (EV_P_ ev_stat *w) +{ + w->wd = inotify_add_watch (fs_fd, w->path, IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY | IN_DONT_FOLLOW | IN_MASK_ADD); + + if (w->wd >= 0) + { + struct statfs sfs; + + /* now local changes will be tracked by inotify, but remote changes won't */ + /* unless the filesystem is known to be local, we therefore still poll */ + /* also do poll on <2.6.25, but with normal frequency */ + + if (!fs_2625) + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + else if (!statfs (w->path, &sfs) + && (sfs.f_type == 0x1373 /* devfs */ + || sfs.f_type == 0xEF53 /* ext2/3 */ + || sfs.f_type == 0x3153464a /* jfs */ + || sfs.f_type == 0x52654973 /* reiser3 */ + || sfs.f_type == 0x01021994 /* tempfs */ + || sfs.f_type == 0x58465342 /* xfs */)) + w->timer.repeat = 0.; /* filesystem is local, kernel new enough */ + else + w->timer.repeat = w->interval ? w->interval : NFS_STAT_INTERVAL; /* remote, use reduced frequency */ + } + else + { + /* can't use inotify, continue to stat */ + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + + /* if path is not there, monitor some parent directory for speedup hints */ + /* note that exceeding the hardcoded path limit is not a correctness issue, */ + /* but an efficiency issue only */ + if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096) + { + char path [4096]; + strcpy (path, w->path); + + do + { + int mask = IN_MASK_ADD | IN_DELETE_SELF | IN_MOVE_SELF + | (errno == EACCES ? IN_ATTRIB : IN_CREATE | IN_MOVED_TO); + + char *pend = strrchr (path, '/'); + + if (!pend || pend == path) + break; + + *pend = 0; + w->wd = inotify_add_watch (fs_fd, path, mask); + } + while (w->wd < 0 && (errno == ENOENT || errno == EACCES)); + } + } + + if (w->wd >= 0) + wlist_add (&fs_hash [w->wd & ((EV_INOTIFY_HASHSIZE) - 1)].head, (WL)w); + + /* now re-arm timer, if required */ + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); +} + +static void noinline +infy_del (EV_P_ ev_stat *w) +{ + int slot; + int wd = w->wd; + + if (wd < 0) + return; + + w->wd = -2; + slot = wd & ((EV_INOTIFY_HASHSIZE) - 1); + wlist_del (&fs_hash [slot].head, (WL)w); + + /* remove this watcher, if others are watching it, they will rearm */ + inotify_rm_watch (fs_fd, wd); +} + +static void noinline +infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev) +{ + if (slot < 0) + /* overflow, need to check for all hash slots */ + for (slot = 0; slot < (EV_INOTIFY_HASHSIZE); ++slot) + infy_wd (EV_A_ slot, wd, ev); + else + { + WL w_; + + for (w_ = fs_hash [slot & ((EV_INOTIFY_HASHSIZE) - 1)].head; w_; ) + { + ev_stat *w = (ev_stat *)w_; + w_ = w_->next; /* lets us remove this watcher and all before it */ + + if (w->wd == wd || wd == -1) + { + if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF)) + { + wlist_del (&fs_hash [slot & ((EV_INOTIFY_HASHSIZE) - 1)].head, (WL)w); + w->wd = -1; + infy_add (EV_A_ w); /* re-add, no matter what */ + } + + stat_timer_cb (EV_A_ &w->timer, 0); + } + } + } +} + +static void +infy_cb (EV_P_ ev_io *w, int revents) +{ + char buf [EV_INOTIFY_BUFSIZE]; + int ofs; + int len = read (fs_fd, buf, sizeof (buf)); + + for (ofs = 0; ofs < len; ) + { + struct inotify_event *ev = (struct inotify_event *)(buf + ofs); + infy_wd (EV_A_ ev->wd, ev->wd, ev); + ofs += sizeof (struct inotify_event) + ev->len; + } +} + +inline_size void +ev_check_2625 (EV_P) +{ + /* kernels < 2.6.25 are borked + * http://www.ussg.indiana.edu/hypermail/linux/kernel/0711.3/1208.html + */ + if (ev_linux_version () < 0x020619) + return; + + fs_2625 = 1; +} + +inline_size int +infy_newfd (void) +{ +#if defined (IN_CLOEXEC) && defined (IN_NONBLOCK) + int fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK); + if (fd >= 0) + return fd; +#endif + return inotify_init (); +} + +inline_size void +infy_init (EV_P) +{ + if (fs_fd != -2) + return; + + fs_fd = -1; + + ev_check_2625 (EV_A); + + fs_fd = infy_newfd (); + + if (fs_fd >= 0) + { + fd_intern (fs_fd); + ev_io_init (&fs_w, infy_cb, fs_fd, EV_READ); + ev_set_priority (&fs_w, EV_MAXPRI); + ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); + } +} + +inline_size void +infy_fork (EV_P) +{ + int slot; + + if (fs_fd < 0) + return; + + ev_ref (EV_A); + ev_io_stop (EV_A_ &fs_w); + close (fs_fd); + fs_fd = infy_newfd (); + + if (fs_fd >= 0) + { + fd_intern (fs_fd); + ev_io_set (&fs_w, fs_fd, EV_READ); + ev_io_start (EV_A_ &fs_w); + ev_unref (EV_A); + } + + for (slot = 0; slot < (EV_INOTIFY_HASHSIZE); ++slot) + { + WL w_ = fs_hash [slot].head; + fs_hash [slot].head = 0; + + while (w_) + { + ev_stat *w = (ev_stat *)w_; + w_ = w_->next; /* lets us add this watcher */ + + w->wd = -1; + + if (fs_fd >= 0) + infy_add (EV_A_ w); /* re-add, no matter what */ + else + { + w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL; + if (ev_is_active (&w->timer)) ev_ref (EV_A); + ev_timer_again (EV_A_ &w->timer); + if (ev_is_active (&w->timer)) ev_unref (EV_A); + } + } + } +} + +#endif + +#ifdef _WIN32 +# define EV_LSTAT(p,b) _stati64 (p, b) +#else +# define EV_LSTAT(p,b) lstat (p, b) +#endif + +void +ev_stat_stat (EV_P_ ev_stat *w) +{ + if (lstat (w->path, &w->attr) < 0) + w->attr.st_nlink = 0; + else if (!w->attr.st_nlink) + w->attr.st_nlink = 1; +} + +static void noinline +stat_timer_cb (EV_P_ ev_timer *w_, int revents) +{ + ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer)); + + ev_statdata prev = w->attr; + ev_stat_stat (EV_A_ w); + + /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */ + if ( + prev.st_dev != w->attr.st_dev + || prev.st_ino != w->attr.st_ino + || prev.st_mode != w->attr.st_mode + || prev.st_nlink != w->attr.st_nlink + || prev.st_uid != w->attr.st_uid + || prev.st_gid != w->attr.st_gid + || prev.st_rdev != w->attr.st_rdev + || prev.st_size != w->attr.st_size + || prev.st_atime != w->attr.st_atime + || prev.st_mtime != w->attr.st_mtime + || prev.st_ctime != w->attr.st_ctime + ) { + /* we only update w->prev on actual differences */ + /* in case we test more often than invoke the callback, */ + /* to ensure that prev is always different to attr */ + w->prev = prev; + + #if EV_USE_INOTIFY + if (fs_fd >= 0) + { + infy_del (EV_A_ w); + infy_add (EV_A_ w); + ev_stat_stat (EV_A_ w); /* avoid race... */ + } + #endif + + ev_feed_event (EV_A_ w, EV_STAT); + } +} + +void +ev_stat_start (EV_P_ ev_stat *w) +{ + if (expect_false (ev_is_active (w))) + return; + + ev_stat_stat (EV_A_ w); + + if (w->interval < MIN_STAT_INTERVAL && w->interval) + w->interval = MIN_STAT_INTERVAL; + + ev_timer_init (&w->timer, stat_timer_cb, 0., w->interval ? w->interval : DEF_STAT_INTERVAL); + ev_set_priority (&w->timer, ev_priority (w)); + +#if EV_USE_INOTIFY + infy_init (EV_A); + + if (fs_fd >= 0) + infy_add (EV_A_ w); + else +#endif + { + ev_timer_again (EV_A_ &w->timer); + ev_unref (EV_A); + } + + ev_start (EV_A_ (W)w, 1); + + EV_FREQUENT_CHECK; +} + +void +ev_stat_stop (EV_P_ ev_stat *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + +#if EV_USE_INOTIFY + infy_del (EV_A_ w); +#endif + + if (ev_is_active (&w->timer)) + { + ev_ref (EV_A); + ev_timer_stop (EV_A_ &w->timer); + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_IDLE_ENABLE +void +ev_idle_start (EV_P_ ev_idle *w) +{ + if (expect_false (ev_is_active (w))) + return; + + pri_adjust (EV_A_ (W)w); + + EV_FREQUENT_CHECK; + + { + int active = ++idlecnt [ABSPRI (w)]; + + ++idleall; + ev_start (EV_A_ (W)w, active); + + array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2); + idles [ABSPRI (w)][active - 1] = w; + } + + EV_FREQUENT_CHECK; +} + +void +ev_idle_stop (EV_P_ ev_idle *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + idles [ABSPRI (w)][active - 1] = idles [ABSPRI (w)][--idlecnt [ABSPRI (w)]]; + ev_active (idles [ABSPRI (w)][active - 1]) = active; + + ev_stop (EV_A_ (W)w); + --idleall; + } + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_PREPARE_ENABLE +void +ev_prepare_start (EV_P_ ev_prepare *w) +{ + if (expect_false (ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, ++preparecnt); + array_needsize (ev_prepare *, prepares, preparemax, preparecnt, EMPTY2); + prepares [preparecnt - 1] = w; + + EV_FREQUENT_CHECK; +} + +void +ev_prepare_stop (EV_P_ ev_prepare *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + prepares [active - 1] = prepares [--preparecnt]; + ev_active (prepares [active - 1]) = active; + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_CHECK_ENABLE +void +ev_check_start (EV_P_ ev_check *w) +{ + if (expect_false (ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, ++checkcnt); + array_needsize (ev_check *, checks, checkmax, checkcnt, EMPTY2); + checks [checkcnt - 1] = w; + + EV_FREQUENT_CHECK; +} + +void +ev_check_stop (EV_P_ ev_check *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + checks [active - 1] = checks [--checkcnt]; + ev_active (checks [active - 1]) = active; + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_EMBED_ENABLE +void noinline +ev_embed_sweep (EV_P_ ev_embed *w) +{ + ev_run (w->other, EVRUN_NOWAIT); +} + +static void +embed_io_cb (EV_P_ ev_io *io, int revents) +{ + ev_embed *w = (ev_embed *)(((char *)io) - offsetof (ev_embed, io)); + + if (ev_cb (w)) + ev_feed_event (EV_A_ (W)w, EV_EMBED); + else + ev_run (w->other, EVRUN_NOWAIT); +} + +static void +embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents) +{ + ev_embed *w = (ev_embed *)(((char *)prepare) - offsetof (ev_embed, prepare)); + + { + EV_P = w->other; + + while (fdchangecnt) + { + fd_reify (EV_A); + ev_run (EV_A_ EVRUN_NOWAIT); + } + } +} + +static void +embed_fork_cb (EV_P_ ev_fork *fork_w, int revents) +{ + ev_embed *w = (ev_embed *)(((char *)fork_w) - offsetof (ev_embed, fork)); + + ev_embed_stop (EV_A_ w); + + { + EV_P = w->other; + + ev_loop_fork (EV_A); + ev_run (EV_A_ EVRUN_NOWAIT); + } + + ev_embed_start (EV_A_ w); +} + +#if 0 +static void +embed_idle_cb (EV_P_ ev_idle *idle, int revents) +{ + ev_idle_stop (EV_A_ idle); +} +#endif + +void +ev_embed_start (EV_P_ ev_embed *w) +{ + if (expect_false (ev_is_active (w))) + return; + + { + EV_P = w->other; + assert (("libev: loop to be embedded is not embeddable", backend & ev_embeddable_backends ())); + ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ); + } + + EV_FREQUENT_CHECK; + + ev_set_priority (&w->io, ev_priority (w)); + ev_io_start (EV_A_ &w->io); + + ev_prepare_init (&w->prepare, embed_prepare_cb); + ev_set_priority (&w->prepare, EV_MINPRI); + ev_prepare_start (EV_A_ &w->prepare); + + ev_fork_init (&w->fork, embed_fork_cb); + ev_fork_start (EV_A_ &w->fork); + + /*ev_idle_init (&w->idle, e,bed_idle_cb);*/ + + ev_start (EV_A_ (W)w, 1); + + EV_FREQUENT_CHECK; +} + +void +ev_embed_stop (EV_P_ ev_embed *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_io_stop (EV_A_ &w->io); + ev_prepare_stop (EV_A_ &w->prepare); + ev_fork_stop (EV_A_ &w->fork); + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_FORK_ENABLE +void +ev_fork_start (EV_P_ ev_fork *w) +{ + if (expect_false (ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, ++forkcnt); + array_needsize (ev_fork *, forks, forkmax, forkcnt, EMPTY2); + forks [forkcnt - 1] = w; + + EV_FREQUENT_CHECK; +} + +void +ev_fork_stop (EV_P_ ev_fork *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + forks [active - 1] = forks [--forkcnt]; + ev_active (forks [active - 1]) = active; + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_CLEANUP_ENABLE +void +ev_cleanup_start (EV_P_ ev_cleanup *w) +{ + if (expect_false (ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, ++cleanupcnt); + array_needsize (ev_cleanup *, cleanups, cleanupmax, cleanupcnt, EMPTY2); + cleanups [cleanupcnt - 1] = w; + + /* cleanup watchers should never keep a refcount on the loop */ + ev_unref (EV_A); + EV_FREQUENT_CHECK; +} + +void +ev_cleanup_stop (EV_P_ ev_cleanup *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + ev_ref (EV_A); + + { + int active = ev_active (w); + + cleanups [active - 1] = cleanups [--cleanupcnt]; + ev_active (cleanups [active - 1]) = active; + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} +#endif + +#if EV_ASYNC_ENABLE +void +ev_async_start (EV_P_ ev_async *w) +{ + if (expect_false (ev_is_active (w))) + return; + + w->sent = 0; + + evpipe_init (EV_A); + + EV_FREQUENT_CHECK; + + ev_start (EV_A_ (W)w, ++asynccnt); + array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2); + asyncs [asynccnt - 1] = w; + + EV_FREQUENT_CHECK; +} + +void +ev_async_stop (EV_P_ ev_async *w) +{ + clear_pending (EV_A_ (W)w); + if (expect_false (!ev_is_active (w))) + return; + + EV_FREQUENT_CHECK; + + { + int active = ev_active (w); + + asyncs [active - 1] = asyncs [--asynccnt]; + ev_active (asyncs [active - 1]) = active; + } + + ev_stop (EV_A_ (W)w); + + EV_FREQUENT_CHECK; +} + +void +ev_async_send (EV_P_ ev_async *w) +{ + w->sent = 1; + evpipe_write (EV_A_ &async_pending); +} +#endif + +/*****************************************************************************/ + +struct ev_once +{ + ev_io io; + ev_timer to; + void (*cb)(int revents, void *arg); + void *arg; +}; + +static void +once_cb (EV_P_ struct ev_once *once, int revents) +{ + void (*cb)(int revents, void *arg) = once->cb; + void *arg = once->arg; + + ev_io_stop (EV_A_ &once->io); + ev_timer_stop (EV_A_ &once->to); + ev_free (once); + + cb (revents, arg); +} + +static void +once_cb_io (EV_P_ ev_io *w, int revents) +{ + struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, io)); + + once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->to)); +} + +static void +once_cb_to (EV_P_ ev_timer *w, int revents) +{ + struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, to)); + + once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->io)); +} + +void +ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) +{ + struct ev_once *once = (struct ev_once *)ev_malloc (sizeof (struct ev_once)); + + if (expect_false (!once)) + { + cb (EV_ERROR | EV_READ | EV_WRITE | EV_TIMER, arg); + return; + } + + once->cb = cb; + once->arg = arg; + + ev_init (&once->io, once_cb_io); + if (fd >= 0) + { + ev_io_set (&once->io, fd, events); + ev_io_start (EV_A_ &once->io); + } + + ev_init (&once->to, once_cb_to); + if (timeout >= 0.) + { + ev_timer_set (&once->to, timeout, 0.); + ev_timer_start (EV_A_ &once->to); + } +} + +/*****************************************************************************/ + +#if EV_WALK_ENABLE +void +ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) +{ + int i, j; + ev_watcher_list *wl, *wn; + + if (types & (EV_IO | EV_EMBED)) + for (i = 0; i < anfdmax; ++i) + for (wl = anfds [i].head; wl; ) + { + wn = wl->next; + +#if EV_EMBED_ENABLE + if (ev_cb ((ev_io *)wl) == embed_io_cb) + { + if (types & EV_EMBED) + cb (EV_A_ EV_EMBED, ((char *)wl) - offsetof (struct ev_embed, io)); + } + else +#endif +#if EV_USE_INOTIFY + if (ev_cb ((ev_io *)wl) == infy_cb) + ; + else +#endif + if ((ev_io *)wl != &pipe_w) + if (types & EV_IO) + cb (EV_A_ EV_IO, wl); + + wl = wn; + } + + if (types & (EV_TIMER | EV_STAT)) + for (i = timercnt + HEAP0; i-- > HEAP0; ) +#if EV_STAT_ENABLE + /*TODO: timer is not always active*/ + if (ev_cb ((ev_timer *)ANHE_w (timers [i])) == stat_timer_cb) + { + if (types & EV_STAT) + cb (EV_A_ EV_STAT, ((char *)ANHE_w (timers [i])) - offsetof (struct ev_stat, timer)); + } + else +#endif + if (types & EV_TIMER) + cb (EV_A_ EV_TIMER, ANHE_w (timers [i])); + +#if EV_PERIODIC_ENABLE + if (types & EV_PERIODIC) + for (i = periodiccnt + HEAP0; i-- > HEAP0; ) + cb (EV_A_ EV_PERIODIC, ANHE_w (periodics [i])); +#endif + +#if EV_IDLE_ENABLE + if (types & EV_IDLE) + for (j = NUMPRI; i--; ) + for (i = idlecnt [j]; i--; ) + cb (EV_A_ EV_IDLE, idles [j][i]); +#endif + +#if EV_FORK_ENABLE + if (types & EV_FORK) + for (i = forkcnt; i--; ) + if (ev_cb (forks [i]) != embed_fork_cb) + cb (EV_A_ EV_FORK, forks [i]); +#endif + +#if EV_ASYNC_ENABLE + if (types & EV_ASYNC) + for (i = asynccnt; i--; ) + cb (EV_A_ EV_ASYNC, asyncs [i]); +#endif + +#if EV_PREPARE_ENABLE + if (types & EV_PREPARE) + for (i = preparecnt; i--; ) +# if EV_EMBED_ENABLE + if (ev_cb (prepares [i]) != embed_prepare_cb) +# endif + cb (EV_A_ EV_PREPARE, prepares [i]); +#endif + +#if EV_CHECK_ENABLE + if (types & EV_CHECK) + for (i = checkcnt; i--; ) + cb (EV_A_ EV_CHECK, checks [i]); +#endif + +#if EV_SIGNAL_ENABLE + if (types & EV_SIGNAL) + for (i = 0; i < EV_NSIG - 1; ++i) + for (wl = signals [i].head; wl; ) + { + wn = wl->next; + cb (EV_A_ EV_SIGNAL, wl); + wl = wn; + } +#endif + +#if EV_CHILD_ENABLE + if (types & EV_CHILD) + for (i = (EV_PID_HASHSIZE); i--; ) + for (wl = childs [i]; wl; ) + { + wn = wl->next; + cb (EV_A_ EV_CHILD, wl); + wl = wn; + } +#endif +/* EV_STAT 0x00001000 /* stat data changed */ +/* EV_EMBED 0x00010000 /* embedded event loop needs sweep */ +} +#endif + +#if EV_MULTIPLICITY + #include "ev_wrap.h" +#endif + +EV_CPP(}) + diff --git a/src/util/verto/ev.h b/src/util/verto/ev.h new file mode 100644 index 0000000000..27c1778f1f --- /dev/null +++ b/src/util/verto/ev.h @@ -0,0 +1,829 @@ +/* + * libev native API header + * + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifndef EV_H_ +#define EV_H_ + +#ifdef __cplusplus +# define EV_CPP(x) x +#else +# define EV_CPP(x) +#endif + +EV_CPP(extern "C" {) + +/*****************************************************************************/ + +/* pre-4.0 compatibility */ +#ifndef EV_COMPAT3 +# define EV_COMPAT3 1 +#endif + +#ifndef EV_FEATURES +# define EV_FEATURES 0x7f +#endif + +#define EV_FEATURE_CODE ((EV_FEATURES) & 1) +#define EV_FEATURE_DATA ((EV_FEATURES) & 2) +#define EV_FEATURE_CONFIG ((EV_FEATURES) & 4) +#define EV_FEATURE_API ((EV_FEATURES) & 8) +#define EV_FEATURE_WATCHERS ((EV_FEATURES) & 16) +#define EV_FEATURE_BACKENDS ((EV_FEATURES) & 32) +#define EV_FEATURE_OS ((EV_FEATURES) & 64) + +/* these priorities are inclusive, higher priorities will be invoked earlier */ +#ifndef EV_MINPRI +# define EV_MINPRI (EV_FEATURE_CONFIG ? -2 : 0) +#endif +#ifndef EV_MAXPRI +# define EV_MAXPRI (EV_FEATURE_CONFIG ? +2 : 0) +#endif + +#ifndef EV_MULTIPLICITY +# define EV_MULTIPLICITY EV_FEATURE_CONFIG +#endif + +#ifndef EV_PERIODIC_ENABLE +# define EV_PERIODIC_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_STAT_ENABLE +# define EV_STAT_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_PREPARE_ENABLE +# define EV_PREPARE_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_CHECK_ENABLE +# define EV_CHECK_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_IDLE_ENABLE +# define EV_IDLE_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_FORK_ENABLE +# define EV_FORK_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_CLEANUP_ENABLE +# define EV_CLEANUP_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_SIGNAL_ENABLE +# define EV_SIGNAL_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_CHILD_ENABLE +# ifdef _WIN32 +# define EV_CHILD_ENABLE 0 +# else +# define EV_CHILD_ENABLE EV_FEATURE_WATCHERS +#endif +#endif + +#ifndef EV_ASYNC_ENABLE +# define EV_ASYNC_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_EMBED_ENABLE +# define EV_EMBED_ENABLE EV_FEATURE_WATCHERS +#endif + +#ifndef EV_WALK_ENABLE +# define EV_WALK_ENABLE 0 /* not yet */ +#endif + +/*****************************************************************************/ + +#if EV_CHILD_ENABLE && !EV_SIGNAL_ENABLE +# undef EV_SIGNAL_ENABLE +# define EV_SIGNAL_ENABLE 1 +#endif + +/*****************************************************************************/ + +typedef double ev_tstamp; + +#ifndef EV_ATOMIC_T +# include +# define EV_ATOMIC_T sig_atomic_t volatile +#endif + +#if EV_STAT_ENABLE +# ifdef _WIN32 +# include +# include +# endif +# include +#endif + +/* support multiple event loops? */ +#if EV_MULTIPLICITY +struct ev_loop; +# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */ +# define EV_P_ EV_P, /* a loop as first of multiple parameters */ +# define EV_A loop /* a loop as sole argument to a function call */ +# define EV_A_ EV_A, /* a loop as first of multiple arguments */ +# define EV_DEFAULT_UC ev_default_loop_uc_ () /* the default loop, if initialised, as sole arg */ +# define EV_DEFAULT_UC_ EV_DEFAULT_UC, /* the default loop as first of multiple arguments */ +# define EV_DEFAULT ev_default_loop (0) /* the default loop as sole arg */ +# define EV_DEFAULT_ EV_DEFAULT, /* the default loop as first of multiple arguments */ +#else +# define EV_P void +# define EV_P_ +# define EV_A +# define EV_A_ +# define EV_DEFAULT +# define EV_DEFAULT_ +# define EV_DEFAULT_UC +# define EV_DEFAULT_UC_ +# undef EV_EMBED_ENABLE +#endif + +/* EV_INLINE is used for functions in header files */ +#if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3 +# define EV_INLINE static inline +#else +# define EV_INLINE static +#endif + +/* EV_PROTOTYPES can be used to switch of prototype declarations */ +#ifndef EV_PROTOTYPES +# define EV_PROTOTYPES 1 +#endif + +/*****************************************************************************/ + +#define EV_VERSION_MAJOR 4 +#define EV_VERSION_MINOR 4 + +/* eventmask, revents, events... */ +enum { + EV_UNDEF = 0xFFFFFFFF, /* guaranteed to be invalid */ + EV_NONE = 0x00, /* no events */ + EV_READ = 0x01, /* ev_io detected read will not block */ + EV_WRITE = 0x02, /* ev_io detected write will not block */ + EV__IOFDSET = 0x80, /* internal use only */ + EV_IO = EV_READ, /* alias for type-detection */ + EV_TIMER = 0x00000100, /* timer timed out */ +#if EV_COMPAT3 + EV_TIMEOUT = EV_TIMER, /* pre 4.0 API compatibility */ +#endif + EV_PERIODIC = 0x00000200, /* periodic timer timed out */ + EV_SIGNAL = 0x00000400, /* signal was received */ + EV_CHILD = 0x00000800, /* child/pid had status change */ + EV_STAT = 0x00001000, /* stat data changed */ + EV_IDLE = 0x00002000, /* event loop is idling */ + EV_PREPARE = 0x00004000, /* event loop about to poll */ + EV_CHECK = 0x00008000, /* event loop finished poll */ + EV_EMBED = 0x00010000, /* embedded event loop needs sweep */ + EV_FORK = 0x00020000, /* event loop resumed in child */ + EV_CLEANUP = 0x00040000, /* event loop resumed in child */ + EV_ASYNC = 0x00080000, /* async intra-loop signal */ + EV_CUSTOM = 0x01000000, /* for use by user code */ + EV_ERROR = 0x80000000 /* sent when an error occurs */ +}; + +/* can be used to add custom fields to all watchers, while losing binary compatibility */ +#ifndef EV_COMMON +# define EV_COMMON void *data; +#endif + +#ifndef EV_CB_DECLARE +# define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); +#endif +#ifndef EV_CB_INVOKE +# define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents)) +#endif + +/* not official, do not use */ +#define EV_CB(type,name) void name (EV_P_ struct ev_ ## type *w, int revents) + +/* + * struct member types: + * private: you may look at them, but not change them, + * and they might not mean anything to you. + * ro: can be read anytime, but only changed when the watcher isn't active. + * rw: can be read and modified anytime, even when the watcher is active. + * + * some internal details that might be helpful for debugging: + * + * active is either 0, which means the watcher is not active, + * or the array index of the watcher (periodics, timers) + * or the array index + 1 (most other watchers) + * or simply 1 for watchers that aren't in some array. + * pending is either 0, in which case the watcher isn't, + * or the array index + 1 in the pendings array. + */ + +#if EV_MINPRI == EV_MAXPRI +# define EV_DECL_PRIORITY +#elif !defined (EV_DECL_PRIORITY) +# define EV_DECL_PRIORITY int priority; +#endif + +/* shared by all watchers */ +#define EV_WATCHER(type) \ + int active; /* private */ \ + int pending; /* private */ \ + EV_DECL_PRIORITY /* private */ \ + EV_COMMON /* rw */ \ + EV_CB_DECLARE (type) /* private */ + +#define EV_WATCHER_LIST(type) \ + EV_WATCHER (type) \ + struct ev_watcher_list *next; /* private */ + +#define EV_WATCHER_TIME(type) \ + EV_WATCHER (type) \ + ev_tstamp at; /* private */ + +/* base class, nothing to see here unless you subclass */ +typedef struct ev_watcher +{ + EV_WATCHER (ev_watcher) +} ev_watcher; + +/* base class, nothing to see here unless you subclass */ +typedef struct ev_watcher_list +{ + EV_WATCHER_LIST (ev_watcher_list) +} ev_watcher_list; + +/* base class, nothing to see here unless you subclass */ +typedef struct ev_watcher_time +{ + EV_WATCHER_TIME (ev_watcher_time) +} ev_watcher_time; + +/* invoked when fd is either EV_READable or EV_WRITEable */ +/* revent EV_READ, EV_WRITE */ +typedef struct ev_io +{ + EV_WATCHER_LIST (ev_io) + + int fd; /* ro */ + int events; /* ro */ +} ev_io; + +/* invoked after a specific time, repeatable (based on monotonic clock) */ +/* revent EV_TIMEOUT */ +typedef struct ev_timer +{ + EV_WATCHER_TIME (ev_timer) + + ev_tstamp repeat; /* rw */ +} ev_timer; + +/* invoked at some specific time, possibly repeating at regular intervals (based on UTC) */ +/* revent EV_PERIODIC */ +typedef struct ev_periodic +{ + EV_WATCHER_TIME (ev_periodic) + + ev_tstamp offset; /* rw */ + ev_tstamp interval; /* rw */ + ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now); /* rw */ +} ev_periodic; + +/* invoked when the given signal has been received */ +/* revent EV_SIGNAL */ +typedef struct ev_signal +{ + EV_WATCHER_LIST (ev_signal) + + int signum; /* ro */ +} ev_signal; + +/* invoked when sigchld is received and waitpid indicates the given pid */ +/* revent EV_CHILD */ +/* does not support priorities */ +typedef struct ev_child +{ + EV_WATCHER_LIST (ev_child) + + int flags; /* private */ + int pid; /* ro */ + int rpid; /* rw, holds the received pid */ + int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */ +} ev_child; + +#if EV_STAT_ENABLE +/* st_nlink = 0 means missing file or other error */ +# ifdef _WIN32 +typedef struct _stati64 ev_statdata; +# else +typedef struct stat ev_statdata; +# endif + +/* invoked each time the stat data changes for a given path */ +/* revent EV_STAT */ +typedef struct ev_stat +{ + EV_WATCHER_LIST (ev_stat) + + ev_timer timer; /* private */ + ev_tstamp interval; /* ro */ + const char *path; /* ro */ + ev_statdata prev; /* ro */ + ev_statdata attr; /* ro */ + + int wd; /* wd for inotify, fd for kqueue */ +} ev_stat; +#endif + +#if EV_IDLE_ENABLE +/* invoked when the nothing else needs to be done, keeps the process from blocking */ +/* revent EV_IDLE */ +typedef struct ev_idle +{ + EV_WATCHER (ev_idle) +} ev_idle; +#endif + +/* invoked for each run of the mainloop, just before the blocking call */ +/* you can still change events in any way you like */ +/* revent EV_PREPARE */ +typedef struct ev_prepare +{ + EV_WATCHER (ev_prepare) +} ev_prepare; + +/* invoked for each run of the mainloop, just after the blocking call */ +/* revent EV_CHECK */ +typedef struct ev_check +{ + EV_WATCHER (ev_check) +} ev_check; + +#if EV_FORK_ENABLE +/* the callback gets invoked before check in the child process when a fork was detected */ +/* revent EV_FORK */ +typedef struct ev_fork +{ + EV_WATCHER (ev_fork) +} ev_fork; +#endif + +#if EV_CLEANUP_ENABLE +/* is invoked just before the loop gets destroyed */ +/* revent EV_CLEANUP */ +typedef struct ev_cleanup +{ + EV_WATCHER (ev_cleanup) +} ev_cleanup; +#endif + +#if EV_EMBED_ENABLE +/* used to embed an event loop inside another */ +/* the callback gets invoked when the event loop has handled events, and can be 0 */ +typedef struct ev_embed +{ + EV_WATCHER (ev_embed) + + struct ev_loop *other; /* ro */ + ev_io io; /* private */ + ev_prepare prepare; /* private */ + ev_check check; /* unused */ + ev_timer timer; /* unused */ + ev_periodic periodic; /* unused */ + ev_idle idle; /* unused */ + ev_fork fork; /* private */ +#if EV_CLEANUP_ENABLE + ev_cleanup cleanup; /* unused */ +#endif +} ev_embed; +#endif + +#if EV_ASYNC_ENABLE +/* invoked when somebody calls ev_async_send on the watcher */ +/* revent EV_ASYNC */ +typedef struct ev_async +{ + EV_WATCHER (ev_async) + + EV_ATOMIC_T sent; /* private */ +} ev_async; + +# define ev_async_pending(w) (+(w)->sent) +#endif + +/* the presence of this union forces similar struct layout */ +union ev_any_watcher +{ + struct ev_watcher w; + struct ev_watcher_list wl; + + struct ev_io io; + struct ev_timer timer; + struct ev_periodic periodic; + struct ev_signal signal; + struct ev_child child; +#if EV_STAT_ENABLE + struct ev_stat stat; +#endif +#if EV_IDLE_ENABLE + struct ev_idle idle; +#endif + struct ev_prepare prepare; + struct ev_check check; +#if EV_FORK_ENABLE + struct ev_fork fork; +#endif +#if EV_CLEANUP_ENABLE + struct ev_cleanup cleanup; +#endif +#if EV_EMBED_ENABLE + struct ev_embed embed; +#endif +#if EV_ASYNC_ENABLE + struct ev_async async; +#endif +}; + +/* flag bits for ev_default_loop and ev_loop_new */ +enum { + /* the default */ + EVFLAG_AUTO = 0x00000000U, /* not quite a mask */ + /* flag bits */ + EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */ + EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */ + /* debugging/feature disable */ + EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */ +#if EV_COMPAT3 + EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ +#endif + EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ + EVFLAG_NOSIGMASK = 0x00400000U /* avoid modifying the signal mask */ +}; + +/* method bits to be ored together */ +enum { + EVBACKEND_SELECT = 0x00000001U, /* about anywhere */ + EVBACKEND_POLL = 0x00000002U, /* !win */ + EVBACKEND_EPOLL = 0x00000004U, /* linux */ + EVBACKEND_KQUEUE = 0x00000008U, /* bsd */ + EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */ + EVBACKEND_PORT = 0x00000020U, /* solaris 10 */ + EVBACKEND_ALL = 0x0000003FU, /* all known backends */ + EVBACKEND_MASK = 0x0000FFFFU /* all future backends */ +}; + +#if EV_PROTOTYPES +int ev_version_major (void); +int ev_version_minor (void); + +unsigned int ev_supported_backends (void); +unsigned int ev_recommended_backends (void); +unsigned int ev_embeddable_backends (void); + +ev_tstamp ev_time (void); +void ev_sleep (ev_tstamp delay); /* sleep for a while */ + +/* Sets the allocation function to use, works like realloc. + * It is used to allocate and free memory. + * If it returns zero when memory needs to be allocated, the library might abort + * or take some potentially destructive action. + * The default is your system realloc function. + */ +void ev_set_allocator (void *(*cb)(void *ptr, long size)); + +/* set the callback function to call on a + * retryable syscall error + * (such as failed select, poll, epoll_wait) + */ +void ev_set_syserr_cb (void (*cb)(const char *msg)); + +#if EV_MULTIPLICITY + +/* the default loop is the only one that handles signals and child watchers */ +/* you can call this as often as you like */ +struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)); + +EV_INLINE struct ev_loop * +ev_default_loop_uc_ (void) +{ + extern struct ev_loop *ev_default_loop_ptr; + + return ev_default_loop_ptr; +} + +EV_INLINE int +ev_is_default_loop (EV_P) +{ + return EV_A == EV_DEFAULT_UC; +} + +/* create and destroy alternative loops that don't handle signals */ +struct ev_loop *ev_loop_new (unsigned int flags EV_CPP (= 0)); + +ev_tstamp ev_now (EV_P); /* time w.r.t. timers and the eventloop, updated after each poll */ + +#else + +int ev_default_loop (unsigned int flags EV_CPP (= 0)); /* returns true when successful */ + +EV_INLINE ev_tstamp +ev_now (void) +{ + extern ev_tstamp ev_rt_now; + + return ev_rt_now; +} + +/* looks weird, but ev_is_default_loop (EV_A) still works if this exists */ +EV_INLINE int +ev_is_default_loop (void) +{ + return 1; +} + +#endif /* multiplicity */ + +/* destroy event loops, also works for the default loop */ +void ev_loop_destroy (EV_P); + +/* this needs to be called after fork, to duplicate the loop */ +/* when you want to re-use it in the child */ +/* you can call it in either the parent or the child */ +/* you can actually call it at any time, anywhere :) */ +void ev_loop_fork (EV_P); + +unsigned int ev_backend (EV_P); /* backend in use by loop */ + +void ev_now_update (EV_P); /* update event loop time */ + +#if EV_WALK_ENABLE +/* walk (almost) all watchers in the loop of a given type, invoking the */ +/* callback on every such watcher. The callback might stop the watcher, */ +/* but do nothing else with the loop */ +void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)); +#endif + +#endif /* prototypes */ + +/* ev_run flags values */ +enum { + EVRUN_NOWAIT = 1, /* do not block/wait */ + EVRUN_ONCE = 2 /* block *once* only */ +}; + +/* ev_break how values */ +enum { + EVBREAK_CANCEL = 0, /* undo unloop */ + EVBREAK_ONE = 1, /* unloop once */ + EVBREAK_ALL = 2 /* unloop all loops */ +}; + +#if EV_PROTOTYPES +void ev_run (EV_P_ int flags EV_CPP (= 0)); +void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)); /* break out of the loop */ + +/* + * ref/unref can be used to add or remove a refcount on the mainloop. every watcher + * keeps one reference. if you have a long-running watcher you never unregister that + * should not keep ev_loop from running, unref() after starting, and ref() before stopping. + */ +void ev_ref (EV_P); +void ev_unref (EV_P); + +/* + * convenience function, wait for a single event, without registering an event watcher + * if timeout is < 0, do wait indefinitely + */ +void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); + +# if EV_FEATURE_API +unsigned int ev_iteration (EV_P); /* number of loop iterations */ +unsigned int ev_depth (EV_P); /* #ev_loop enters - #ev_loop leaves */ +void ev_verify (EV_P); /* abort if loop data corrupted */ + +void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ +void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ + +/* advanced stuff for threading etc. support, see docs */ +void ev_set_userdata (EV_P_ void *data); +void *ev_userdata (EV_P); +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)); +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)); + +unsigned int ev_pending_count (EV_P); /* number of pending events, if any */ +void ev_invoke_pending (EV_P); /* invoke all pending watchers */ + +/* + * stop/start the timer handling. + */ +void ev_suspend (EV_P); +void ev_resume (EV_P); +#endif + +#endif + +/* these may evaluate ev multiple times, and the other arguments at most once */ +/* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ +#define ev_init(ev,cb_) do { \ + ((ev_watcher *)(void *)(ev))->active = \ + ((ev_watcher *)(void *)(ev))->pending = 0; \ + ev_set_priority ((ev), 0); \ + ev_set_cb ((ev), cb_); \ +} while (0) + +#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0) +#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0) +#define ev_periodic_set(ev,ofs_,ival_,rcb_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb = (rcb_); } while (0) +#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0) +#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0) +#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0) +#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */ +#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */ +#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */ +#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0) +#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */ +#define ev_cleanup_set(ev) /* nop, yes, this is a serious in-joke */ +#define ev_async_set(ev) /* nop, yes, this is a serious in-joke */ + +#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0) +#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0) +#define ev_periodic_init(ev,cb,ofs,ival,rcb) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(ofs),(ival),(rcb)); } while (0) +#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0) +#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0) +#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0) +#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0) +#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0) +#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0) +#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0) +#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0) +#define ev_cleanup_init(ev,cb) do { ev_init ((ev), (cb)); ev_cleanup_set ((ev)); } while (0) +#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0) + +#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ +#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ + +#define ev_cb(ev) (ev)->cb /* rw */ + +#if EV_MINPRI == EV_MAXPRI +# define ev_priority(ev) ((ev), EV_MINPRI) +# define ev_set_priority(ev,pri) ((ev), (pri)) +#else +# define ev_priority(ev) (+(((ev_watcher *)(void *)(ev))->priority)) +# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri) +#endif + +#define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at) + +#ifndef ev_set_cb +# define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_) +#endif + +/* stopping (enabling, adding) a watcher does nothing if it is already running */ +/* stopping (disabling, deleting) a watcher does nothing unless its already running */ +#if EV_PROTOTYPES + +/* feeds an event into a watcher as if the event actually occured */ +/* accepts any ev_watcher type */ +void ev_feed_event (EV_P_ void *w, int revents); +void ev_feed_fd_event (EV_P_ int fd, int revents); +#if EV_SIGNAL_ENABLE +void ev_feed_signal (int signum); +void ev_feed_signal_event (EV_P_ int signum); +#endif +void ev_invoke (EV_P_ void *w, int revents); +int ev_clear_pending (EV_P_ void *w); + +void ev_io_start (EV_P_ ev_io *w); +void ev_io_stop (EV_P_ ev_io *w); + +void ev_timer_start (EV_P_ ev_timer *w); +void ev_timer_stop (EV_P_ ev_timer *w); +/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ +void ev_timer_again (EV_P_ ev_timer *w); +/* return remaining time */ +ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w); + +#if EV_PERIODIC_ENABLE +void ev_periodic_start (EV_P_ ev_periodic *w); +void ev_periodic_stop (EV_P_ ev_periodic *w); +void ev_periodic_again (EV_P_ ev_periodic *w); +#endif + +/* only supported in the default loop */ +#if EV_SIGNAL_ENABLE +void ev_signal_start (EV_P_ ev_signal *w); +void ev_signal_stop (EV_P_ ev_signal *w); +#endif + +/* only supported in the default loop */ +# if EV_CHILD_ENABLE +void ev_child_start (EV_P_ ev_child *w); +void ev_child_stop (EV_P_ ev_child *w); +# endif + +# if EV_STAT_ENABLE +void ev_stat_start (EV_P_ ev_stat *w); +void ev_stat_stop (EV_P_ ev_stat *w); +void ev_stat_stat (EV_P_ ev_stat *w); +# endif + +# if EV_IDLE_ENABLE +void ev_idle_start (EV_P_ ev_idle *w); +void ev_idle_stop (EV_P_ ev_idle *w); +# endif + +#if EV_PREPARE_ENABLE +void ev_prepare_start (EV_P_ ev_prepare *w); +void ev_prepare_stop (EV_P_ ev_prepare *w); +#endif + +#if EV_CHECK_ENABLE +void ev_check_start (EV_P_ ev_check *w); +void ev_check_stop (EV_P_ ev_check *w); +#endif + +# if EV_FORK_ENABLE +void ev_fork_start (EV_P_ ev_fork *w); +void ev_fork_stop (EV_P_ ev_fork *w); +# endif + +# if EV_CLEANUP_ENABLE +void ev_cleanup_start (EV_P_ ev_cleanup *w); +void ev_cleanup_stop (EV_P_ ev_cleanup *w); +# endif + +# if EV_EMBED_ENABLE +/* only supported when loop to be embedded is in fact embeddable */ +void ev_embed_start (EV_P_ ev_embed *w); +void ev_embed_stop (EV_P_ ev_embed *w); +void ev_embed_sweep (EV_P_ ev_embed *w); +# endif + +# if EV_ASYNC_ENABLE +void ev_async_start (EV_P_ ev_async *w); +void ev_async_stop (EV_P_ ev_async *w); +void ev_async_send (EV_P_ ev_async *w); +# endif + +#if EV_COMPAT3 + #define EVLOOP_NONBLOCK EVRUN_NOWAIT + #define EVLOOP_ONESHOT EVRUN_ONCE + #define EVUNLOOP_CANCEL EVBREAK_CANCEL + #define EVUNLOOP_ONE EVBREAK_ONE + #define EVUNLOOP_ALL EVBREAK_ALL + #if EV_PROTOTYPES + EV_INLINE void ev_loop (EV_P_ int flags) { ev_run (EV_A_ flags); } + EV_INLINE void ev_unloop (EV_P_ int how ) { ev_break (EV_A_ how ); } + EV_INLINE void ev_default_destroy (void) { ev_loop_destroy (EV_DEFAULT); } + EV_INLINE void ev_default_fork (void) { ev_loop_fork (EV_DEFAULT); } + #if EV_FEATURE_API + EV_INLINE unsigned int ev_loop_count (EV_P) { return ev_iteration (EV_A); } + EV_INLINE unsigned int ev_loop_depth (EV_P) { return ev_depth (EV_A); } + EV_INLINE void ev_loop_verify (EV_P) { ev_verify (EV_A); } + #endif + #endif +#else + typedef struct ev_loop ev_loop; +#endif + +#endif + +EV_CPP(}) + +#endif + diff --git a/src/util/verto/ev_poll.c b/src/util/verto/ev_poll.c new file mode 100644 index 0000000000..e53ae0de93 --- /dev/null +++ b/src/util/verto/ev_poll.c @@ -0,0 +1,148 @@ +/* + * libev poll fd activity backend + * + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#include + +void inline_size +pollidx_init (int *base, int count) +{ + /* consider using memset (.., -1, ...), which is practically guaranteed + * to work on all systems implementing poll */ + while (count--) + *base++ = -1; +} + +static void +poll_modify (EV_P_ int fd, int oev, int nev) +{ + int idx; + + if (oev == nev) + return; + + array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init); + + idx = pollidxs [fd]; + + if (idx < 0) /* need to allocate a new pollfd */ + { + pollidxs [fd] = idx = pollcnt++; + array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2); + polls [idx].fd = fd; + } + + assert (polls [idx].fd == fd); + + if (nev) + polls [idx].events = + (nev & EV_READ ? POLLIN : 0) + | (nev & EV_WRITE ? POLLOUT : 0); + else /* remove pollfd */ + { + pollidxs [fd] = -1; + + if (expect_true (idx < --pollcnt)) + { + polls [idx] = polls [pollcnt]; + pollidxs [polls [idx].fd] = idx; + } + } +} + +static void +poll_poll (EV_P_ ev_tstamp timeout) +{ + struct pollfd *p; + int res; + + EV_RELEASE_CB; + res = poll (polls, pollcnt, ev_timeout_to_ms (timeout)); + EV_ACQUIRE_CB; + + if (expect_false (res < 0)) + { + if (errno == EBADF) + fd_ebadf (EV_A); + else if (errno == ENOMEM && !syserr_cb) + fd_enomem (EV_A); + else if (errno != EINTR) + ev_syserr ("(libev) poll"); + } + else + for (p = polls; res; ++p) + { + assert (("libev: poll() returned illegal result, broken BSD kernel?", p < polls + pollcnt)); + + if (expect_false (p->revents)) /* this expect is debatable */ + { + --res; + + if (expect_false (p->revents & POLLNVAL)) + fd_kill (EV_A_ p->fd); + else + fd_event ( + EV_A_ + p->fd, + (p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) + | (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) + ); + } + } +} + +int inline_size +poll_init (EV_P_ int flags) +{ + backend_fudge = 0.; /* posix says this is zero */ + backend_modify = poll_modify; + backend_poll = poll_poll; + + pollidxs = 0; pollidxmax = 0; + polls = 0; pollmax = 0; pollcnt = 0; + + return EVBACKEND_POLL; +} + +void inline_size +poll_destroy (EV_P) +{ + ev_free (pollidxs); + ev_free (polls); +} + diff --git a/src/util/verto/ev_select.c b/src/util/verto/ev_select.c new file mode 100644 index 0000000000..0ea9467e40 --- /dev/null +++ b/src/util/verto/ev_select.c @@ -0,0 +1,310 @@ +/* + * libev select fd activity backend + * + * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifndef _WIN32 +/* for unix systems */ +# include +# ifndef __hpux +/* for REAL unix systems */ +# include +# endif +#endif + +#ifndef EV_SELECT_USE_FD_SET +# ifdef NFDBITS +# define EV_SELECT_USE_FD_SET 0 +# else +# define EV_SELECT_USE_FD_SET 1 +# endif +#endif + +#if EV_SELECT_IS_WINSOCKET +# undef EV_SELECT_USE_FD_SET +# define EV_SELECT_USE_FD_SET 1 +# undef NFDBITS +# define NFDBITS 0 +#endif + +#if !EV_SELECT_USE_FD_SET +# define NFDBYTES (NFDBITS / 8) +#endif + +#include + +static void +select_modify (EV_P_ int fd, int oev, int nev) +{ + if (oev == nev) + return; + + { +#if EV_SELECT_USE_FD_SET + + #if EV_SELECT_IS_WINSOCKET + SOCKET handle = anfds [fd].handle; + #else + int handle = fd; + #endif + + assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE)); + + /* FD_SET is broken on windows (it adds the fd to a set twice or more, + * which eventually leads to overflows). Need to call it only on changes. + */ + #if EV_SELECT_IS_WINSOCKET + if ((oev ^ nev) & EV_READ) + #endif + if (nev & EV_READ) + FD_SET (handle, (fd_set *)vec_ri); + else + FD_CLR (handle, (fd_set *)vec_ri); + + #if EV_SELECT_IS_WINSOCKET + if ((oev ^ nev) & EV_WRITE) + #endif + if (nev & EV_WRITE) + FD_SET (handle, (fd_set *)vec_wi); + else + FD_CLR (handle, (fd_set *)vec_wi); + +#else + + int word = fd / NFDBITS; + fd_mask mask = 1UL << (fd % NFDBITS); + + if (expect_false (vec_max <= word)) + { + int new_max = word + 1; + + vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES); + vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */ + vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES); + vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */ + #ifdef _WIN32 + vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */ + #endif + + for (; vec_max < new_max; ++vec_max) + ((fd_mask *)vec_ri) [vec_max] = + ((fd_mask *)vec_wi) [vec_max] = 0; + } + + ((fd_mask *)vec_ri) [word] |= mask; + if (!(nev & EV_READ)) + ((fd_mask *)vec_ri) [word] &= ~mask; + + ((fd_mask *)vec_wi) [word] |= mask; + if (!(nev & EV_WRITE)) + ((fd_mask *)vec_wi) [word] &= ~mask; +#endif + } +} + +static void +select_poll (EV_P_ ev_tstamp timeout) +{ + struct timeval tv; + int res; + int fd_setsize; + + EV_RELEASE_CB; + EV_TV_SET (tv, timeout); + +#if EV_SELECT_USE_FD_SET + fd_setsize = sizeof (fd_set); +#else + fd_setsize = vec_max * NFDBYTES; +#endif + + memcpy (vec_ro, vec_ri, fd_setsize); + memcpy (vec_wo, vec_wi, fd_setsize); + +#ifdef _WIN32 + /* pass in the write set as except set. + * the idea behind this is to work around a windows bug that causes + * errors to be reported as an exception and not by setting + * the writable bit. this is so uncontrollably lame. + */ + memcpy (vec_eo, vec_wi, fd_setsize); + res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv); +#elif EV_SELECT_USE_FD_SET + fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE; + res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); +#else + res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); +#endif + EV_ACQUIRE_CB; + + if (expect_false (res < 0)) + { + #if EV_SELECT_IS_WINSOCKET + errno = WSAGetLastError (); + #endif + #ifdef WSABASEERR + /* on windows, select returns incompatible error codes, fix this */ + if (errno >= WSABASEERR && errno < WSABASEERR + 1000) + if (errno == WSAENOTSOCK) + errno = EBADF; + else + errno -= WSABASEERR; + #endif + + #ifdef _WIN32 + /* select on windows erroneously returns EINVAL when no fd sets have been + * provided (this is documented). what microsoft doesn't tell you that this bug + * exists even when the fd sets _are_ provided, so we have to check for this bug + * here and emulate by sleeping manually. + * we also get EINVAL when the timeout is invalid, but we ignore this case here + * and assume that EINVAL always means: you have to wait manually. + */ + if (errno == EINVAL) + { + ev_sleep (timeout); + return; + } + #endif + + if (errno == EBADF) + fd_ebadf (EV_A); + else if (errno == ENOMEM && !syserr_cb) + fd_enomem (EV_A); + else if (errno != EINTR) + ev_syserr ("(libev) select"); + + return; + } + +#if EV_SELECT_USE_FD_SET + + { + int fd; + + for (fd = 0; fd < anfdmax; ++fd) + if (anfds [fd].events) + { + int events = 0; + #if EV_SELECT_IS_WINSOCKET + SOCKET handle = anfds [fd].handle; + #else + int handle = fd; + #endif + + if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ; + if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE; + #ifdef _WIN32 + if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE; + #endif + + if (expect_true (events)) + fd_event (EV_A_ fd, events); + } + } + +#else + + { + int word, bit; + for (word = vec_max; word--; ) + { + fd_mask word_r = ((fd_mask *)vec_ro) [word]; + fd_mask word_w = ((fd_mask *)vec_wo) [word]; + #ifdef _WIN32 + word_w |= ((fd_mask *)vec_eo) [word]; + #endif + + if (word_r || word_w) + for (bit = NFDBITS; bit--; ) + { + fd_mask mask = 1UL << bit; + int events = 0; + + events |= word_r & mask ? EV_READ : 0; + events |= word_w & mask ? EV_WRITE : 0; + + if (expect_true (events)) + fd_event (EV_A_ word * NFDBITS + bit, events); + } + } + } + +#endif +} + +int inline_size +select_init (EV_P_ int flags) +{ + backend_fudge = 0.; /* posix says this is zero */ + backend_modify = select_modify; + backend_poll = select_poll; + +#if EV_SELECT_USE_FD_SET + vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); + vec_ro = ev_malloc (sizeof (fd_set)); + vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi); + vec_wo = ev_malloc (sizeof (fd_set)); + #ifdef _WIN32 + vec_eo = ev_malloc (sizeof (fd_set)); + #endif +#else + vec_max = 0; + vec_ri = 0; + vec_ro = 0; + vec_wi = 0; + vec_wo = 0; + #ifdef _WIN32 + vec_eo = 0; + #endif +#endif + + return EVBACKEND_SELECT; +} + +void inline_size +select_destroy (EV_P) +{ + ev_free (vec_ri); + ev_free (vec_ro); + ev_free (vec_wi); + ev_free (vec_wo); + #ifdef _WIN32 + ev_free (vec_eo); + #endif +} + + diff --git a/src/util/verto/ev_vars.h b/src/util/verto/ev_vars.h new file mode 100644 index 0000000000..5ee3ed1b2a --- /dev/null +++ b/src/util/verto/ev_vars.h @@ -0,0 +1,203 @@ +/* + * loop member variable declarations + * + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#define VARx(type,name) VAR(name, type name) + +VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */ +VARx(ev_tstamp, mn_now) /* monotonic clock "now" */ +VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ + +VARx(ev_tstamp, io_blocktime) +VARx(ev_tstamp, timeout_blocktime) + +VARx(int, backend) +VARx(int, activecnt) /* total number of active events ("refcount") */ +VARx(EV_ATOMIC_T, loop_done) /* signal by ev_break */ + +VARx(int, backend_fd) +VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */ +VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev)) +VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout)) + +VARx(ANFD *, anfds) +VARx(int, anfdmax) + +VAR (pendings, ANPENDING *pendings [NUMPRI]) +VAR (pendingmax, int pendingmax [NUMPRI]) +VAR (pendingcnt, int pendingcnt [NUMPRI]) +VARx(ev_prepare, pending_w) /* dummy pending watcher */ + +/* for reverse feeding of events */ +VARx(W *, rfeeds) +VARx(int, rfeedmax) +VARx(int, rfeedcnt) + +#if EV_USE_EVENTFD || EV_GENWRAP +VARx(int, evfd) +#endif +VAR (evpipe, int evpipe [2]) +VARx(ev_io, pipe_w) + +#if !defined(_WIN32) || EV_GENWRAP +VARx(pid_t, curpid) +#endif + +VARx(char, postfork) /* true if we need to recreate kernel state after fork */ + +#if EV_USE_SELECT || EV_GENWRAP +VARx(void *, vec_ri) +VARx(void *, vec_ro) +VARx(void *, vec_wi) +VARx(void *, vec_wo) +#if defined(_WIN32) || EV_GENWRAP +VARx(void *, vec_eo) +#endif +VARx(int, vec_max) +#endif + +#if EV_USE_POLL || EV_GENWRAP +VARx(struct pollfd *, polls) +VARx(int, pollmax) +VARx(int, pollcnt) +VARx(int *, pollidxs) /* maps fds into structure indices */ +VARx(int, pollidxmax) +#endif + +#if EV_USE_EPOLL || EV_GENWRAP +VARx(struct epoll_event *, epoll_events) +VARx(int, epoll_eventmax) +VARx(int *, epoll_eperms) +VARx(int, epoll_epermcnt) +VARx(int, epoll_epermmax) +#endif + +#if EV_USE_KQUEUE || EV_GENWRAP +VARx(struct kevent *, kqueue_changes) +VARx(int, kqueue_changemax) +VARx(int, kqueue_changecnt) +VARx(struct kevent *, kqueue_events) +VARx(int, kqueue_eventmax) +#endif + +#if EV_USE_PORT || EV_GENWRAP +VARx(struct port_event *, port_events) +VARx(int, port_eventmax) +#endif + +#if EV_USE_IOCP || EV_GENWRAP +VARx(HANDLE, iocp) +#endif + +VARx(int *, fdchanges) +VARx(int, fdchangemax) +VARx(int, fdchangecnt) + +VARx(ANHE *, timers) +VARx(int, timermax) +VARx(int, timercnt) + +#if EV_PERIODIC_ENABLE || EV_GENWRAP +VARx(ANHE *, periodics) +VARx(int, periodicmax) +VARx(int, periodiccnt) +#endif + +#if EV_IDLE_ENABLE || EV_GENWRAP +VAR (idles, ev_idle **idles [NUMPRI]) +VAR (idlemax, int idlemax [NUMPRI]) +VAR (idlecnt, int idlecnt [NUMPRI]) +#endif +VARx(int, idleall) /* total number */ + +VARx(struct ev_prepare **, prepares) +VARx(int, preparemax) +VARx(int, preparecnt) + +VARx(struct ev_check **, checks) +VARx(int, checkmax) +VARx(int, checkcnt) + +#if EV_FORK_ENABLE || EV_GENWRAP +VARx(struct ev_fork **, forks) +VARx(int, forkmax) +VARx(int, forkcnt) +#endif + +#if EV_CLEANUP_ENABLE || EV_GENWRAP +VARx(struct ev_cleanup **, cleanups) +VARx(int, cleanupmax) +VARx(int, cleanupcnt) +#endif + +#if EV_ASYNC_ENABLE || EV_GENWRAP +VARx(EV_ATOMIC_T, async_pending) +VARx(struct ev_async **, asyncs) +VARx(int, asyncmax) +VARx(int, asynccnt) +#endif + +#if EV_USE_INOTIFY || EV_GENWRAP +VARx(int, fs_fd) +VARx(ev_io, fs_w) +VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ +VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) +#endif + +VARx(EV_ATOMIC_T, sig_pending) +VARx(int, nosigmask) +#if EV_USE_SIGNALFD || EV_GENWRAP +VARx(int, sigfd) +VARx(ev_io, sigfd_w) +VARx(sigset_t, sigfd_set) +#endif + +VARx(unsigned int, origflags) /* original loop flags */ + +#if EV_FEATURE_API || EV_GENWRAP +VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ +VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ + +VARx(void *, userdata) +VAR (release_cb, void (*release_cb)(EV_P)) +VAR (acquire_cb, void (*acquire_cb)(EV_P)) +VAR (invoke_cb , void (*invoke_cb) (EV_P)) +#endif + +#undef VARx + diff --git a/src/util/verto/ev_win32.c b/src/util/verto/ev_win32.c new file mode 100644 index 0000000000..338886efe4 --- /dev/null +++ b/src/util/verto/ev_win32.c @@ -0,0 +1,153 @@ +/* + * libev win32 compatibility cruft (_not_ a backend) + * + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifdef _WIN32 + +/* timeb.h is actually xsi legacy functionality */ +#include + +/* note: the comment below could not be substantiated, but what would I care */ +/* MSDN says this is required to handle SIGFPE */ +/* my wild guess would be that using something floating-pointy is required */ +/* for the crt to do something about it */ +volatile double SIGFPE_REQ = 0.0f; + +/* oh, the humanity! */ +static int +ev_pipe (int filedes [2]) +{ + struct sockaddr_in addr = { 0 }; + int addr_size = sizeof (addr); + struct sockaddr_in adr2; + int adr2_size = sizeof (adr2); + SOCKET listener; + SOCKET sock [2] = { -1, -1 }; + + if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) + return -1; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + addr.sin_port = 0; + + if (bind (listener, (struct sockaddr *)&addr, addr_size)) + goto fail; + + if (getsockname (listener, (struct sockaddr *)&addr, &addr_size)) + goto fail; + + if (listen (listener, 1)) + goto fail; + + if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) + goto fail; + + if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) + goto fail; + + if ((sock [1] = accept (listener, 0, 0)) < 0) + goto fail; + + /* windows vista returns fantasy port numbers for sockets: + * example for two interconnected tcp sockets: + * + * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364 + * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363 + * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363 + * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365 + * + * wow! tridirectional sockets! + * + * this way of checking ports seems to work: + */ + if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size)) + goto fail; + + if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size)) + goto fail; + + errno = WSAEINVAL; + if (addr_size != adr2_size + || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */ + || addr.sin_port != adr2.sin_port) + goto fail; + + closesocket (listener); + +#if EV_SELECT_IS_WINSOCKET + filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]); + filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]); +#else + /* when select isn't winsocket, we also expect socket, connect, accept etc. + * to work on fds */ + filedes [0] = sock [0]; + filedes [1] = sock [1]; +#endif + + return 0; + +fail: + closesocket (listener); + + if (sock [0] != INVALID_SOCKET) closesocket (sock [0]); + if (sock [1] != INVALID_SOCKET) closesocket (sock [1]); + + return -1; +} + +#undef pipe +#define pipe(filedes) ev_pipe (filedes) + +#define EV_HAVE_EV_TIME 1 +ev_tstamp +ev_time (void) +{ + FILETIME ft; + ULARGE_INTEGER ui; + + GetSystemTimeAsFileTime (&ft); + ui.u.LowPart = ft.dwLowDateTime; + ui.u.HighPart = ft.dwHighDateTime; + + /* msvc cannot convert ulonglong to double... yes, it is that sucky */ + return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7; +} + +#endif + diff --git a/src/util/verto/ev_wrap.h b/src/util/verto/ev_wrap.h new file mode 100644 index 0000000000..2c195c5db4 --- /dev/null +++ b/src/util/verto/ev_wrap.h @@ -0,0 +1,196 @@ +/* DO NOT EDIT, automatically generated by update_ev_wrap */ +#ifndef EV_WRAP_H +#define EV_WRAP_H +#define now_floor ((loop)->now_floor) +#define mn_now ((loop)->mn_now) +#define rtmn_diff ((loop)->rtmn_diff) +#define io_blocktime ((loop)->io_blocktime) +#define timeout_blocktime ((loop)->timeout_blocktime) +#define backend ((loop)->backend) +#define activecnt ((loop)->activecnt) +#define loop_done ((loop)->loop_done) +#define backend_fd ((loop)->backend_fd) +#define backend_fudge ((loop)->backend_fudge) +#define backend_modify ((loop)->backend_modify) +#define backend_poll ((loop)->backend_poll) +#define anfds ((loop)->anfds) +#define anfdmax ((loop)->anfdmax) +#define pendings ((loop)->pendings) +#define pendingmax ((loop)->pendingmax) +#define pendingcnt ((loop)->pendingcnt) +#define pending_w ((loop)->pending_w) +#define rfeeds ((loop)->rfeeds) +#define rfeedmax ((loop)->rfeedmax) +#define rfeedcnt ((loop)->rfeedcnt) +#define evfd ((loop)->evfd) +#define evpipe ((loop)->evpipe) +#define pipe_w ((loop)->pipe_w) +#define curpid ((loop)->curpid) +#define postfork ((loop)->postfork) +#define vec_ri ((loop)->vec_ri) +#define vec_ro ((loop)->vec_ro) +#define vec_wi ((loop)->vec_wi) +#define vec_wo ((loop)->vec_wo) +#define vec_eo ((loop)->vec_eo) +#define vec_max ((loop)->vec_max) +#define polls ((loop)->polls) +#define pollmax ((loop)->pollmax) +#define pollcnt ((loop)->pollcnt) +#define pollidxs ((loop)->pollidxs) +#define pollidxmax ((loop)->pollidxmax) +#define epoll_events ((loop)->epoll_events) +#define epoll_eventmax ((loop)->epoll_eventmax) +#define epoll_eperms ((loop)->epoll_eperms) +#define epoll_epermcnt ((loop)->epoll_epermcnt) +#define epoll_epermmax ((loop)->epoll_epermmax) +#define kqueue_changes ((loop)->kqueue_changes) +#define kqueue_changemax ((loop)->kqueue_changemax) +#define kqueue_changecnt ((loop)->kqueue_changecnt) +#define kqueue_events ((loop)->kqueue_events) +#define kqueue_eventmax ((loop)->kqueue_eventmax) +#define port_events ((loop)->port_events) +#define port_eventmax ((loop)->port_eventmax) +#define iocp ((loop)->iocp) +#define fdchanges ((loop)->fdchanges) +#define fdchangemax ((loop)->fdchangemax) +#define fdchangecnt ((loop)->fdchangecnt) +#define timers ((loop)->timers) +#define timermax ((loop)->timermax) +#define timercnt ((loop)->timercnt) +#define periodics ((loop)->periodics) +#define periodicmax ((loop)->periodicmax) +#define periodiccnt ((loop)->periodiccnt) +#define idles ((loop)->idles) +#define idlemax ((loop)->idlemax) +#define idlecnt ((loop)->idlecnt) +#define idleall ((loop)->idleall) +#define prepares ((loop)->prepares) +#define preparemax ((loop)->preparemax) +#define preparecnt ((loop)->preparecnt) +#define checks ((loop)->checks) +#define checkmax ((loop)->checkmax) +#define checkcnt ((loop)->checkcnt) +#define forks ((loop)->forks) +#define forkmax ((loop)->forkmax) +#define forkcnt ((loop)->forkcnt) +#define cleanups ((loop)->cleanups) +#define cleanupmax ((loop)->cleanupmax) +#define cleanupcnt ((loop)->cleanupcnt) +#define async_pending ((loop)->async_pending) +#define asyncs ((loop)->asyncs) +#define asyncmax ((loop)->asyncmax) +#define asynccnt ((loop)->asynccnt) +#define fs_fd ((loop)->fs_fd) +#define fs_w ((loop)->fs_w) +#define fs_2625 ((loop)->fs_2625) +#define fs_hash ((loop)->fs_hash) +#define sig_pending ((loop)->sig_pending) +#define nosigmask ((loop)->nosigmask) +#define sigfd ((loop)->sigfd) +#define sigfd_w ((loop)->sigfd_w) +#define sigfd_set ((loop)->sigfd_set) +#define origflags ((loop)->origflags) +#define loop_count ((loop)->loop_count) +#define loop_depth ((loop)->loop_depth) +#define userdata ((loop)->userdata) +#define release_cb ((loop)->release_cb) +#define acquire_cb ((loop)->acquire_cb) +#define invoke_cb ((loop)->invoke_cb) +#else +#undef EV_WRAP_H +#undef now_floor +#undef mn_now +#undef rtmn_diff +#undef io_blocktime +#undef timeout_blocktime +#undef backend +#undef activecnt +#undef loop_done +#undef backend_fd +#undef backend_fudge +#undef backend_modify +#undef backend_poll +#undef anfds +#undef anfdmax +#undef pendings +#undef pendingmax +#undef pendingcnt +#undef pending_w +#undef rfeeds +#undef rfeedmax +#undef rfeedcnt +#undef evfd +#undef evpipe +#undef pipe_w +#undef curpid +#undef postfork +#undef vec_ri +#undef vec_ro +#undef vec_wi +#undef vec_wo +#undef vec_eo +#undef vec_max +#undef polls +#undef pollmax +#undef pollcnt +#undef pollidxs +#undef pollidxmax +#undef epoll_events +#undef epoll_eventmax +#undef epoll_eperms +#undef epoll_epermcnt +#undef epoll_epermmax +#undef kqueue_changes +#undef kqueue_changemax +#undef kqueue_changecnt +#undef kqueue_events +#undef kqueue_eventmax +#undef port_events +#undef port_eventmax +#undef iocp +#undef fdchanges +#undef fdchangemax +#undef fdchangecnt +#undef timers +#undef timermax +#undef timercnt +#undef periodics +#undef periodicmax +#undef periodiccnt +#undef idles +#undef idlemax +#undef idlecnt +#undef idleall +#undef prepares +#undef preparemax +#undef preparecnt +#undef checks +#undef checkmax +#undef checkcnt +#undef forks +#undef forkmax +#undef forkcnt +#undef cleanups +#undef cleanupmax +#undef cleanupcnt +#undef async_pending +#undef asyncs +#undef asyncmax +#undef asynccnt +#undef fs_fd +#undef fs_w +#undef fs_2625 +#undef fs_hash +#undef sig_pending +#undef nosigmask +#undef sigfd +#undef sigfd_w +#undef sigfd_set +#undef origflags +#undef loop_count +#undef loop_depth +#undef userdata +#undef release_cb +#undef acquire_cb +#undef invoke_cb +#endif diff --git a/src/util/verto/module.c b/src/util/verto/module.c index d5977cbbc9..68dc7093de 100644 --- a/src/util/verto/module.c +++ b/src/util/verto/module.c @@ -22,138 +22,25 @@ * SOFTWARE. */ -#ifdef WIN32 -#include -#define dlltype HMODULE -static char * -dllerror(void) { - char *amsg; - LPTSTR msg; +/* Stub implementation of module loading for MIT krb5 bundled libverto. */ - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &msg, 0, NULL); - amsg = strdup((const char*) msg); - LocalFree(msg); - return amsg; -} -#elif defined(aix) -#include "sys/ldr.h" - -struct Dl_info { - const char* dli_fname; -}; - -static int -dladdr(void* s, Dl_info* i) -{ - static const size_t bufSize = 4096; - G__FastAllocString buf(bufSize); - char* pldi = buf; - int r; - - r = loadquery(L_GETINFO, pldi, bufSize); - if (r == -1) { - i->dli_fname = NULL; - return 0; - } - - for (ld_info* ldi = (ld_info*) buf; - ldi->ldinfo_next; - ldi += ldi->ldinfo_next) { - char* textBegin = (char*) ldi->ldinfo_textorg; - if (textBegin < s) { - char* textEnd = textBegin + ldi->ldinfo_textsize; - if (textEnd > s) { - i->dli_fname = ldi->ldinfo_filename; - return 1; - } - } - } - - // First is main(), skip. - ld_info* ldi = (ld_info*) pldi; - while (ldi->ldinfo_next) { - pldi += ldi->ldinfo_next; - ldi = (ld_info*) pldi; - - } - - i->dli_fname = NULL; - return 0; -} -#else -#define _GNU_SOURCE -#include #include -#include -#define dlltype void * -#define dllerror() strdup(dlerror()) -#endif int module_symbol_is_present(const char *modname, const char *symbname) { -#ifdef WIN32 - return (GetProcAddress(GetModuleHandle(modname), symbname) != NULL || - GetProcAddress(GetModuleHandle(NULL), symbname) != NULL); -#else /* WIN32 */ - void* mod = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL); - if (mod) { - void* sym = dlsym(mod, symbname); - dlclose(mod); - return sym != NULL; - } -#endif /* WIN32 */ return 0; } int module_get_filename_for_symbol(void *addr, char **filename) { -#ifdef WIN32 - MEMORY_BASIC_INFORMATION info; - HMODULE mod; - char tmp[MAX_PATH]; - - if (!VirtualQuery(addr, &info, sizeof(info))) - return 0; - mod = (HMODULE) info.AllocationBase; - - if (!GetModuleFileNameA(mod, tmp, MAX_PATH)) - return 0; -#else - const char *tmp; - Dl_info dlinfo; - - if (!dladdr(addr, &dlinfo)) - return 0; - tmp = dlinfo.dli_fname; -#endif - - if (filename) { - *filename = strdup(tmp); - if (!*filename) - return 0; - } - - return 1; + return 0; } void module_close(void *dll) { - if (!dll) - return; - -#ifdef WIN32 - FreeLibrary((dlltype) dll); -#else /* WIN32 */ - dlclose((dlltype) dll); -#endif /* WIN32 */ } char * @@ -161,69 +48,9 @@ module_load(const char *filename, const char *symbname, int (*shouldload)(void *symb, void *misc, char **err), void *misc, void **dll, void **symb) { - dlltype intdll = NULL; - void * intsym = NULL; - char * interr = NULL; - if (dll) *dll = NULL; if (symb) *symb = NULL; - - /* Open the module library */ -#ifdef WIN32 - /* NOTE: DONT_RESOLVE_DLL_REFERENCES is evil. Don't use this in your own - * code. However, our design pattern avoids all the issues surrounding a - * more general use of this evil flag. */ - intdll = LoadLibraryEx(filename, NULL, DONT_RESOLVE_DLL_REFERENCES); -#else /* WIN32 */ - intdll = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); -#endif /* WIN32 */ - if (!intdll) - return dllerror(); - - /* Get the module symbol */ -#ifdef WIN32 - intsym = (void *) GetProcAddress(intdll, symbname); -#else /* WIN32 */ - intsym = dlsym(intdll, symbname); -#endif /* WIN32 */ - if (!intsym) { - module_close(intdll); - return dllerror(); - } - - /* Figure out whether or not to load this module */ - if (!shouldload(intsym, misc, &interr)) { - module_close(intdll); - return interr; - } - - /* Re-open the module */ - module_close(intdll); -#ifdef WIN32 - intdll = LoadLibrary(filename); -#else /* WIN32 */ - intdll = dlopen(filename, RTLD_NOW | RTLD_LOCAL); -#endif /* WIN32 */ - if (!intdll) { - return dllerror(); - } - - /* Get the symbol again */ -#ifdef WIN32 - intsym = (void *) GetProcAddress(intdll, symbname); -#else /* WIN32 */ - intsym = dlsym(intdll, symbname); -#endif /* WIN32 */ - if (!intsym) { - module_close(intdll); - return dllerror(); - } - - if (dll) - *dll = intdll; - if (symb) - *symb = intsym; - return NULL; + return strdup("module loading disabled"); } diff --git a/src/util/verto/verto-k5ev.c b/src/util/verto/verto-k5ev.c new file mode 100644 index 0000000000..f75e8aad6c --- /dev/null +++ b/src/util/verto/verto-k5ev.c @@ -0,0 +1,212 @@ +/* + * Copyright 2011 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * An edited version of verto-libev.c, using an embedded libev with renamed + * symbols. The corresponding version of verto-libev.c is stored in this + * directory for reference, although it is not built here. + */ + +#include +#include +#include + +#include +#include +#include "rename.h" +#include "autoconf.h" +#define EV_STANDALONE 1 +/* Avoid using clock_gettime, which would create a dependency on librt. */ +#define EV_USE_MONOTONIC 0 +#define EV_USE_REALTIME 0 +#define EV_FEATURES 0x5f /* Everything but back ends */ +#ifdef HAVE_POLL_H +#define EV_USE_POLL 1 +#endif +/* ev.c explicitly disables poll() on Mac or FreeBSD; fall back to select(). */ +#define EV_USE_SELECT 1 +#include "ev.c" + +static verto_mod_ctx * +k5ev_ctx_new(void) +{ + return ev_loop_new(EVFLAG_AUTO); +} + +static verto_mod_ctx * +k5ev_ctx_default(void) +{ + return ev_default_loop(EVFLAG_AUTO); +} + +static void +k5ev_ctx_free(verto_mod_ctx *ctx) +{ + if (ctx != EV_DEFAULT) + ev_loop_destroy(ctx); +} + +static void +k5ev_ctx_run(verto_mod_ctx *ctx) +{ + ev_run(ctx, 0); +} + +static void +k5ev_ctx_run_once(verto_mod_ctx *ctx) +{ + ev_run(ctx, EVRUN_ONCE); +} + +static void +k5ev_ctx_break(verto_mod_ctx *ctx) +{ + ev_break(ctx, EVBREAK_ONE); +} + +static void +k5ev_ctx_reinitialize(verto_mod_ctx *ctx) +{ + ev_loop_fork(ctx); +} + +static void +libev_callback(EV_P_ ev_watcher *w, int revents) +{ + verto_ev_flag state = VERTO_EV_FLAG_NONE; + + if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD) + verto_set_proc_status(w->data, ((ev_child*) w)->rstatus); + + if (revents & EV_READ) + state |= VERTO_EV_FLAG_IO_READ; + if (revents & EV_WRITE) + state |= VERTO_EV_FLAG_IO_WRITE; + if (revents & EV_ERROR) + state |= VERTO_EV_FLAG_IO_ERROR; + + verto_set_fd_state(w->data, state); + verto_fire(w->data); +} + +static void +k5ev_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev, + verto_mod_ev *evpriv) +{ + if (verto_get_type(ev) == VERTO_EV_TYPE_IO) { + int events = EV_NONE; + + if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ) + events |= EV_READ; + if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE) + events |= EV_WRITE; + + ev_io_stop(ctx, (ev_io*) evpriv); + ev_io_set(((ev_io*) evpriv), verto_get_fd(ev), events); + ev_io_start(ctx, (ev_io*) evpriv); + } +} + +#define setuptype(type, ...) \ + w.type = malloc(sizeof(ev_ ## type)); \ + if (w.type) { \ + ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \ + ev_ ## type ## _start(ctx, w.type); \ + } \ + break + +static verto_mod_ev * +k5ev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags) +{ + union { + ev_watcher *watcher; + ev_io *io; + ev_timer *timer; + ev_idle *idle; + ev_signal *signal; + ev_child *child; + } w; + ev_tstamp interval; + + w.watcher = NULL; + *flags |= VERTO_EV_FLAG_PERSIST; + switch (verto_get_type(ev)) { + case VERTO_EV_TYPE_IO: + setuptype(io, libev_callback, verto_get_fd(ev), EV_NONE); + case VERTO_EV_TYPE_TIMEOUT: + interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0; + setuptype(timer, libev_callback, interval, interval); + case VERTO_EV_TYPE_IDLE: + setuptype(idle, libev_callback); + case VERTO_EV_TYPE_SIGNAL: + setuptype(signal, libev_callback, verto_get_signal(ev)); + case VERTO_EV_TYPE_CHILD: + *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ + setuptype(child, libev_callback, verto_get_proc(ev), 0); + default: + break; /* Not supported */ + } + + if (w.watcher) { + w.watcher->data = (void*) ev; + k5ev_ctx_set_flags(ctx, ev, w.watcher); + } + return w.watcher; +} + +static void +k5ev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv) +{ + switch (verto_get_type(ev)) { + case VERTO_EV_TYPE_IO: + ev_io_stop(ctx, (ev_io*) evpriv); + break; + case VERTO_EV_TYPE_TIMEOUT: + ev_timer_stop(ctx, (ev_timer*) evpriv); + break; + case VERTO_EV_TYPE_IDLE: + ev_idle_stop(ctx, (ev_idle*) evpriv); + break; + case VERTO_EV_TYPE_SIGNAL: + ev_signal_stop(ctx, (ev_signal*) evpriv); + break; + case VERTO_EV_TYPE_CHILD: + ev_child_stop(ctx, (ev_child*) evpriv); + break; + default: + break; + } + + free(evpriv); +} + +verto_ctx *verto_new_k5ev(void); +verto_ctx *verto_default_k5ev(void); + +VERTO_MODULE(k5ev, NULL, + VERTO_EV_TYPE_IO | + VERTO_EV_TYPE_TIMEOUT | + VERTO_EV_TYPE_IDLE | + VERTO_EV_TYPE_SIGNAL | + VERTO_EV_TYPE_CHILD); diff --git a/src/util/verto/verto-libev.c b/src/util/verto/verto-libev.c new file mode 100644 index 0000000000..9c7c32449c --- /dev/null +++ b/src/util/verto/verto-libev.c @@ -0,0 +1,199 @@ +/* + * Copyright 2011 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include +#define VERTO_MODULE_TYPES +typedef struct ev_loop verto_mod_ctx; +typedef ev_watcher verto_mod_ev; +#include + +static verto_mod_ctx * +libev_ctx_new(void) +{ + return ev_loop_new(EVFLAG_AUTO); +} + +static verto_mod_ctx * +libev_ctx_default(void) +{ + return ev_default_loop(EVFLAG_AUTO); +} + +static void +libev_ctx_free(verto_mod_ctx *ctx) +{ + if (ctx != EV_DEFAULT) + ev_loop_destroy(ctx); +} + +static void +libev_ctx_run(verto_mod_ctx *ctx) +{ + ev_run(ctx, 0); +} + +static void +libev_ctx_run_once(verto_mod_ctx *ctx) +{ + ev_run(ctx, EVRUN_ONCE); +} + +static void +libev_ctx_break(verto_mod_ctx *ctx) +{ + ev_break(ctx, EVBREAK_ONE); +} + +static void +libev_ctx_reinitialize(verto_mod_ctx *ctx) +{ + ev_loop_fork(ctx); +} + +static void +libev_callback(EV_P_ ev_watcher *w, int revents) +{ + verto_ev_flag state = VERTO_EV_FLAG_NONE; + + if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD) + verto_set_proc_status(w->data, ((ev_child*) w)->rstatus); + + if (revents & EV_READ) + state |= VERTO_EV_FLAG_IO_READ; + if (revents & EV_WRITE) + state |= VERTO_EV_FLAG_IO_WRITE; + if (revents & EV_ERROR) + state |= VERTO_EV_FLAG_IO_ERROR; + + verto_set_fd_state(w->data, state); + verto_fire(w->data); +} + +static void +libev_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev, + verto_mod_ev *evpriv) +{ + if (verto_get_type(ev) == VERTO_EV_TYPE_IO) { + int events = EV_NONE; + + if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ) + events |= EV_READ; + if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE) + events |= EV_WRITE; + + ev_io_stop(ctx, (ev_io*) evpriv); + ev_io_set(((ev_io*) evpriv), verto_get_fd(ev), events); + ev_io_start(ctx, (ev_io*) evpriv); + } +} + +#define setuptype(type, ...) \ + w.type = malloc(sizeof(ev_ ## type)); \ + if (w.type) { \ + ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \ + ev_ ## type ## _start(ctx, w.type); \ + } \ + break + +static verto_mod_ev * +libev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags) +{ + union { + ev_watcher *watcher; + ev_io *io; + ev_timer *timer; + ev_idle *idle; + ev_signal *signal; + ev_child *child; + } w; + ev_tstamp interval; + + w.watcher = NULL; + *flags |= VERTO_EV_FLAG_PERSIST; + switch (verto_get_type(ev)) { + case VERTO_EV_TYPE_IO: + setuptype(io, libev_callback, verto_get_fd(ev), EV_NONE); + case VERTO_EV_TYPE_TIMEOUT: + interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0; + setuptype(timer, libev_callback, interval, interval); + case VERTO_EV_TYPE_IDLE: + setuptype(idle, libev_callback); + case VERTO_EV_TYPE_SIGNAL: + setuptype(signal, libev_callback, verto_get_signal(ev)); + case VERTO_EV_TYPE_CHILD: + *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ + setuptype(child, libev_callback, verto_get_proc(ev), 0); + default: + break; /* Not supported */ + } + + if (w.watcher) { + w.watcher->data = (void*) ev; + libev_ctx_set_flags(ctx, ev, w.watcher); + } + return w.watcher; +} + +static void +libev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv) +{ + switch (verto_get_type(ev)) { + case VERTO_EV_TYPE_IO: + ev_io_stop(ctx, (ev_io*) evpriv); + break; + case VERTO_EV_TYPE_TIMEOUT: + ev_timer_stop(ctx, (ev_timer*) evpriv); + break; + case VERTO_EV_TYPE_IDLE: + ev_idle_stop(ctx, (ev_idle*) evpriv); + break; + case VERTO_EV_TYPE_SIGNAL: + ev_signal_stop(ctx, (ev_signal*) evpriv); + break; + case VERTO_EV_TYPE_CHILD: + ev_child_stop(ctx, (ev_child*) evpriv); + break; + default: + break; + } + + free(evpriv); +} + +VERTO_MODULE(libev, ev_loop_new, + VERTO_EV_TYPE_IO | + VERTO_EV_TYPE_TIMEOUT | + VERTO_EV_TYPE_IDLE | + VERTO_EV_TYPE_SIGNAL | + VERTO_EV_TYPE_CHILD); + +verto_ctx * +verto_convert_libev(struct ev_loop* loop) +{ + return verto_convert(libev, 0, loop); +} -- cgit