summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2012-07-14 19:50:11 +0200
committerEmil Renner Berthing <esmil@mailme.dk>2012-07-23 17:31:17 +0200
commit28916e9f54430ec47bb0a8babb8ec3018143c7ea (patch)
treef420a1cf80abf9931d3ab6c5efb9a9b98bc94cd0
parent744e7b4ec5f3c8b2d26dfb9822429f0dd6fbd77a (diff)
downloadlem-28916e9f54430ec47bb0a8babb8ec3018143c7ea.tar.gz
lem-28916e9f54430ec47bb0a8babb8ec3018143c7ea.tar.xz
lem-28916e9f54430ec47bb0a8babb8ec3018143c7ea.zip
libev: update to v4.11
-rwxr-xr-xlem-repl4
-rw-r--r--libev/Changes45
-rw-r--r--libev/Makefile.am4
-rw-r--r--libev/Makefile.in5
-rw-r--r--libev/Symbols.ev73
-rw-r--r--libev/Symbols.event21
-rw-r--r--libev/autogen.sh5
-rw-r--r--libev/config.h.in8
-rwxr-xr-xlibev/configure455
-rw-r--r--libev/configure.ac17
-rw-r--r--libev/ev++.h10
-rw-r--r--libev/ev.3462
-rw-r--r--libev/ev.c872
-rw-r--r--libev/ev.h176
-rw-r--r--libev/ev.pod436
-rw-r--r--libev/ev_epoll.c39
-rw-r--r--libev/ev_kqueue.c18
-rw-r--r--libev/ev_poll.c16
-rw-r--r--libev/ev_port.c20
-rw-r--r--libev/ev_select.c35
-rw-r--r--libev/ev_vars.h11
-rw-r--r--libev/ev_win32.c12
-rw-r--r--libev/ev_wrap.h10
-rw-r--r--libev/event.c6
-rw-r--r--libev/event.h6
-rw-r--r--libev/libev.m411
26 files changed, 2008 insertions, 769 deletions
diff --git a/lem-repl b/lem-repl
index cd82011..5ab9954 100755
--- a/lem-repl
+++ b/lem-repl
@@ -22,8 +22,8 @@ local repl = require 'lem.repl'
streams.stdout:write([[
A Lua Event Machine 0.2 Copyright 2011-2012 Emil Renner Berthing
-Lua 5.2.0 Copyright (C) 1994-2008 Lua.org, PUC-Rio
-libev 4.03 Copyright (C)2007,2008,2009 Marc Alexander Lehmann
+Lua 5.2.0 Copyright 1994-2008 Lua.org, PUC-Rio
+libev 4.11 Copyright 2007-2011 Marc Alexander Lehmann
]])
repl.go('stdin', streams.stdin, streams.stdout)
diff --git a/libev/Changes b/libev/Changes
index 53bb646..c664503 100644
--- a/libev/Changes
+++ b/libev/Changes
@@ -1,5 +1,46 @@
Revision history for libev, a high-performance and full-featured event loop.
+TODO: ev_loop_wakeup
+TODO: EV_STANDALONE == NO_HASSEL (do not use clock_gettime in ev_standalone)
+
+4.11 Sat Feb 4 19:52:39 CET 2012
+ - INCOMPATIBLE CHANGE: ev_timer_again now clears the pending status, as
+ was documented already, but not implemented in the repeating case.
+ - new compiletime symbols: EV_NO_SMP and EV_NO_THREADS.
+ - fix a race where the workaround against the epoll fork bugs
+ caused signals to not be handled anymore.
+ - correct backend_fudge for most backends, and implement a windows
+ specific workaround to avoid looping because we call both
+ select and Sleep, both with different time resolutions.
+ - document range and guarantees of ev_sleep.
+ - document reasonable ranges for periodics interval and offset.
+ - rename backend_fudge to backend_mintime to avoid future confusion :)
+ - change the default periodic reschedule function to hopefully be more
+ exact and correct even in corner cases or in the far future.
+ - do not rely on -lm anymore: use it when available but use our
+ own floor () if it is missing. This should make it easier to embed,
+ as no external libraries are required.
+ - strategically import macros from libecb and mark rarely-used functions
+ as cache-cold (saving almost 2k code size on typical amd64 setups).
+ - add Symbols.ev and Symbols.event files, that were missing.
+ - fix backend_mintime value for epoll (was 1/1024, is 1/1000 now).
+ - fix #3 "be smart about timeouts" to not "deadlock" when
+ timeout == now, also improve the section overall.
+ - avoid "AVOIDING FINISHING BEFORE RETURNING" idiom.
+ - support new EV_API_STATIC mode to make all libev symbols
+ static.
+ - supply default CFLAGS of -g -O3 with gcc when original CFLAGS
+ were empty.
+
+4.04 Wed Feb 16 09:01:51 CET 2011
+ - fix two problems in the native win32 backend, where reuse of fd's
+ with different underlying handles caused handles not to be removed
+ or added to the select set (analyzed and tested by Bert Belder).
+ - do no rely on ceil() in ev_e?poll.c.
+ - backport libev to HP-UX versions before 11 v3.
+ - configure did not detect nanosleep and clock_gettime properly when
+ they are available in the libc (as opposed to -lrt).
+
4.03 Tue Jan 11 14:37:25 CET 2011
- officially support polling files with all backends.
- support files, /dev/zero etc. the same way as select in the epoll
@@ -85,7 +126,7 @@ Revision history for libev, a high-performance and full-featured event loop.
that this is a race condition regardless of EV_SIGNALFD.
- backport inotify code to C89.
- inotify file descriptors could leak into child processes.
- - ev_stat watchers could keep an errornous extra ref on the loop,
+ - ev_stat watchers could keep an erroneous extra ref on the loop,
preventing exit when unregistering all watchers (testcases
provided by ry@tinyclouds.org).
- implement EV_WIN32_HANDLE_TO_FD and EV_WIN32_CLOSE_FD configuration
@@ -153,7 +194,7 @@ Revision history for libev, a high-performance and full-featured event loop.
Malek Hadj-Ali).
- implement ev_suspend and ev_resume.
- new EV_CUSTOM revents flag for use by applications.
- - add documentation section about priorites.
+ - add documentation section about priorities.
- add a glossary to the dcoumentation.
- extend the ev_fork description slightly.
- optimize a jump out of call_pending.
diff --git a/libev/Makefile.am b/libev/Makefile.am
index 058c2cb..059305b 100644
--- a/libev/Makefile.am
+++ b/libev/Makefile.am
@@ -5,7 +5,7 @@ VERSION_INFO = 4:0:0
EXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \
ev_vars.h ev_wrap.h \
ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c \
- ev.3 ev.pod
+ ev.3 ev.pod Symbols.ev Symbols.event
man_MANS = ev.3
@@ -16,3 +16,5 @@ lib_LTLIBRARIES = libev.la
libev_la_SOURCES = ev.c event.c
libev_la_LDFLAGS = -version-info $(VERSION_INFO)
+ev.3: ev.pod
+ pod2man -n LIBEV -r "libev-$(VERSION)" -c "libev - high performance full featured event loop" -s3 <$< >$@
diff --git a/libev/Makefile.in b/libev/Makefile.in
index 9817a7e..1e15bd8 100644
--- a/libev/Makefile.in
+++ b/libev/Makefile.in
@@ -230,7 +230,7 @@ VERSION_INFO = 4:0:0
EXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \
ev_vars.h ev_wrap.h \
ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c \
- ev.3 ev.pod
+ ev.3 ev.pod Symbols.ev Symbols.event
man_MANS = ev.3
include_HEADERS = ev.h ev++.h event.h
@@ -766,6 +766,9 @@ uninstall-man: uninstall-man3
uninstall-libLTLIBRARIES uninstall-man uninstall-man3
+ev.3: ev.pod
+ pod2man -n LIBEV -r "libev-$(VERSION)" -c "libev - high performance full featured event loop" -s3 <$< >$@
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/libev/Symbols.ev b/libev/Symbols.ev
new file mode 100644
index 0000000..7a29a75
--- /dev/null
+++ b/libev/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/libev/Symbols.event b/libev/Symbols.event
new file mode 100644
index 0000000..c2d16eb
--- /dev/null
+++ b/libev/Symbols.event
@@ -0,0 +1,21 @@
+event_active
+event_add
+event_base_dispatch
+event_base_free
+event_base_loop
+event_base_loopexit
+event_base_once
+event_base_priority_init
+event_base_set
+event_del
+event_dispatch
+event_get_method
+event_get_version
+event_init
+event_loop
+event_loopexit
+event_once
+event_pending
+event_priority_init
+event_priority_set
+event_set
diff --git a/libev/autogen.sh b/libev/autogen.sh
index 087d2aa..8056ee7 100644
--- a/libev/autogen.sh
+++ b/libev/autogen.sh
@@ -1,6 +1,3 @@
#!/bin/sh
-libtoolize --force
-automake --add-missing --force-missing
-autoreconf
-
+autoreconf --install --symlink --force
diff --git a/libev/config.h.in b/libev/config.h.in
index 75da15c..508542b 100644
--- a/libev/config.h.in
+++ b/libev/config.h.in
@@ -3,7 +3,7 @@
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
-/* "use syscall interface for clock_gettime" */
+/* Define to 1 to use the syscall interface for clock_gettime */
#undef HAVE_CLOCK_SYSCALL
/* Define to 1 if you have the <dlfcn.h> header file. */
@@ -15,6 +15,9 @@
/* Define to 1 if you have the `eventfd' function. */
#undef HAVE_EVENTFD
+/* Define to 1 if the floor function is available */
+#undef HAVE_FLOOR
+
/* Define to 1 if you have the `inotify_init' function. */
#undef HAVE_INOTIFY_INIT
@@ -24,9 +27,6 @@
/* Define to 1 if you have the `kqueue' function. */
#undef HAVE_KQUEUE
-/* Define to 1 if you have the `m' library (-lm). */
-#undef HAVE_LIBM
-
/* Define to 1 if you have the `rt' library (-lrt). */
#undef HAVE_LIBRT
diff --git a/libev/configure b/libev/configure
index b776417..b65399d 100755
--- a/libev/configure
+++ b/libev/configure
@@ -763,6 +763,15 @@ FGREP
EGREP
GREP
SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
am__fastdepCC_FALSE
am__fastdepCC_TRUE
CCDEPMODE
@@ -779,15 +788,6 @@ CPPFLAGS
LDFLAGS
CFLAGS
CC
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-LIBTOOL
MAINT
MAINTAINER_MODE_FALSE
MAINTAINER_MODE_TRUE
@@ -856,11 +856,11 @@ ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_maintainer_mode
+enable_dependency_tracking
enable_shared
enable_static
with_pic
enable_fast_install
-enable_dependency_tracking
with_gnu_ld
enable_libtool_lock
'
@@ -1493,12 +1493,12 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
--enable-shared[=PKGS] build shared libraries [default=yes]
--enable-static[=PKGS] build static libraries [default=yes]
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
- --disable-dependency-tracking speeds up one-time build
- --enable-dependency-tracking do not reject slow dependency extractors
--disable-libtool-lock avoid locking (might break parallel builds)
Optional Packages:
@@ -2766,7 +2766,7 @@ fi
# Define the identity of the package.
PACKAGE=libev
- VERSION=4.03
+ VERSION=4.11
cat >>confdefs.h <<_ACEOF
@@ -2831,165 +2831,6 @@ fi
-
-case `pwd` in
- *\ * | *\ *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
-esac
-
-
-
-macro_version='2.2.6b'
-macro_revision='1.3017'
-
-
-
-
-
-
-
-
-
-
-
-
-
-ltmain="$ac_aux_dir/ltmain.sh"
-
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if test "${ac_cv_build+set}" = set; then :
- $as_echo_n "(cached) " >&6
-else
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if test "${ac_cv_host+set}" = set; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
- @echo this is the am__doit target
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
-$as_echo_n "checking for style of include used by $am_make... " >&6; }
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# Ignore all kinds of additional output from `make'.
-case `$am_make -s -f confmf 2> /dev/null` in #(
-*the\ am__doit\ target*)
- am__include=include
- am__quote=
- _am_result=GNU
- ;;
-esac
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
- echo '.include "confinc"' > confmf
- case `$am_make -s -f confmf 2> /dev/null` in #(
- *the\ am__doit\ target*)
- am__include=.include
- am__quote="\""
- _am_result=BSD
- ;;
- esac
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
-$as_echo "$_am_result" >&6; }
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then :
- enableval=$enable_dependency_tracking;
-fi
-
-if test "x$enable_dependency_tracking" != xno; then
- am_depcomp="$ac_aux_dir/depcomp"
- AMDEPBACKSLASH='\'
-fi
- if test "x$enable_dependency_tracking" != xno; then
- AMDEP_TRUE=
- AMDEP_FALSE='#'
-else
- AMDEP_TRUE='#'
- AMDEP_FALSE=
-fi
-
-
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3779,6 +3620,68 @@ ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
depcc="$CC" am_compiler_list=
@@ -3907,6 +3810,110 @@ else
fi
+
+if test -z "$orig_CFLAGS"; then
+ if test x$GCC = xyes; then
+ CFLAGS="-g -O3"
+ fi
+fi
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.6b'
+macro_revision='1.3017'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
if test "${ac_cv_path_SED+set}" = set; then :
@@ -4491,13 +4498,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:4494: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:4501: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:4497: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:4504: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:4500: output\"" >&5)
+ (eval echo "\"\$as_me:4507: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5703,7 +5710,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5706 "configure"' > conftest.$ac_ext
+ echo '#line 5713 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -7228,11 +7235,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7231: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7238: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7235: \$? = $ac_status" >&5
+ echo "$as_me:7242: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7567,11 +7574,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7570: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7577: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7574: \$? = $ac_status" >&5
+ echo "$as_me:7581: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7672,11 +7679,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7675: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7682: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7679: \$? = $ac_status" >&5
+ echo "$as_me:7686: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7727,11 +7734,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7730: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7737: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7734: \$? = $ac_status" >&5
+ echo "$as_me:7741: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -10111,7 +10118,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 10114 "configure"
+#line 10121 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10207,7 +10214,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 10210 "configure"
+#line 10217 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10435,10 +10442,6 @@ CC="$lt_save_CC"
-if test "x$GCC" = xyes ; then
- CFLAGS="-O3 $CFLAGS"
-fi
-
for ac_header in sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/select.h sys/eventfd.h sys/signalfd.h
do :
@@ -10467,8 +10470,13 @@ fi
done
-ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
+for ac_func in clock_gettime
+do :
+ ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
if test "x$ac_cv_func_clock_gettime" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CLOCK_GETTIME 1
+_ACEOF
else
@@ -10563,10 +10571,16 @@ done
fi
fi
+done
-ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
+for ac_func in nanosleep
+do :
+ ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
if test "x$ac_cv_func_nanosleep" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_NANOSLEEP 1
+_ACEOF
else
@@ -10631,15 +10645,18 @@ done
fi
fi
+done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceil in -lm" >&5
-$as_echo_n "checking for ceil in -lm... " >&6; }
-if test "${ac_cv_lib_m_ceil+set}" = set; then :
+if test -z "$LIBEV_M4_AVOID_LIBM"; then
+ LIBM=m
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing floor" >&5
+$as_echo_n "checking for library containing floor... " >&6; }
+if test "${ac_cv_search_floor+set}" = set; then :
$as_echo_n "(cached) " >&6
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm $LIBS"
+ ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -10649,32 +10666,46 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char ceil ();
+char floor ();
int
main ()
{
-return ceil ();
+return floor ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_m_ceil=yes
-else
- ac_cv_lib_m_ceil=no
+for ac_lib in '' $LIBM; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_floor=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ conftest$ac_exeext
+ if test "${ac_cv_search_floor+set}" = set; then :
+ break
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_ceil" >&5
-$as_echo "$ac_cv_lib_m_ceil" >&6; }
-if test "x$ac_cv_lib_m_ceil" = x""yes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBM 1
-_ACEOF
+done
+if test "${ac_cv_search_floor+set}" = set; then :
+
+else
+ ac_cv_search_floor=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_floor" >&5
+$as_echo "$ac_cv_search_floor" >&6; }
+ac_res=$ac_cv_search_floor
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- LIBS="-lm $LIBS"
+$as_echo "#define HAVE_FLOOR 1" >>confdefs.h
fi
diff --git a/libev/configure.ac b/libev/configure.ac
index 5a8ea28..31d0a25 100644
--- a/libev/configure.ac
+++ b/libev/configure.ac
@@ -1,17 +1,24 @@
+orig_CFLAGS="$CFLAGS"
+
AC_INIT
AC_CONFIG_SRCDIR([ev_epoll.c])
-AM_INIT_AUTOMAKE(libev,4.03) dnl also update ev.h!
+AM_INIT_AUTOMAKE(libev,4.11) dnl also update ev.h!
AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE
-AC_PROG_INSTALL
-AC_PROG_LIBTOOL
+AC_PROG_CC
-if test "x$GCC" = xyes ; then
- CFLAGS="-O3 $CFLAGS"
+dnl Supply default CFLAGS, if not specified
+if test -z "$orig_CFLAGS"; then
+ if test x$GCC = xyes; then
+ CFLAGS="-g -O3"
+ fi
fi
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
m4_include([libev.m4])
AC_CONFIG_FILES([Makefile])
diff --git a/libev/ev++.h b/libev/ev++.h
index d85be55..c5a0896 100644
--- a/libev/ev++.h
+++ b/libev/ev++.h
@@ -6,14 +6,14 @@
*
* 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
@@ -517,9 +517,9 @@ namespace ev {
}
};
- inline tstamp now () throw ()
+ inline tstamp now (EV_P) throw ()
{
- return ev_time ();
+ return ev_now (EV_A);
}
inline void delay (tstamp interval) throw ()
diff --git a/libev/ev.3 b/libev/ev.3
index a5c974c..2e3365e 100644
--- a/libev/ev.3
+++ b/libev/ev.3
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
.\"
.\" Standard preamble:
.\" ========================================================================
@@ -124,7 +124,7 @@
.\" ========================================================================
.\"
.IX Title "LIBEV 3"
-.TH LIBEV 3 "2011-01-11" "libev-4.03" "libev - high performance full featured event loop"
+.TH LIBEV 3 "2012-02-04" "libev-4.11" "libev - high performance full featured event loop"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -191,7 +191,7 @@ libev \- a high performance full\-featured event loop written in C
\& // now wait for events to arrive
\& ev_run (loop, 0);
\&
-\& // unloop was called, so exit
+\& // break was called, so exit
\& return 0;
\& }
.Ve
@@ -246,7 +246,7 @@ loop mechanism itself (\f(CW\*(C`ev_idle\*(C'\fR, \f(CW\*(C`ev_embed\*(C'\fR, \f
limited support for fork events (\f(CW\*(C`ev_fork\*(C'\fR).
.PP
It also is quite fast (see this
-<benchmark> comparing it to libevent
+benchmark <http://libev.schmorp.de/bench.html> comparing it to libevent
for example).
.SS "\s-1CONVENTIONS\s0"
.IX Subsection "CONVENTIONS"
@@ -296,12 +296,18 @@ library in any way.
Returns the current time as libev would use it. Please note that the
\&\f(CW\*(C`ev_now\*(C'\fR function is usually faster and also often returns the timestamp
you actually want to know. Also interesting is the combination of
-\&\f(CW\*(C`ev_update_now\*(C'\fR and \f(CW\*(C`ev_now\*(C'\fR.
+\&\f(CW\*(C`ev_now_update\*(C'\fR and \f(CW\*(C`ev_now\*(C'\fR.
.IP "ev_sleep (ev_tstamp interval)" 4
.IX Item "ev_sleep (ev_tstamp interval)"
-Sleep for the given interval: The current thread will be blocked until
-either it is interrupted or the given time interval has passed. Basically
-this is a sub-second-resolution \f(CW\*(C`sleep ()\*(C'\fR.
+Sleep for the given interval: The current thread will be blocked
+until either it is interrupted or the given time interval has
+passed (approximately \- it might return a bit earlier even if not
+interrupted). Returns immediately if \f(CW\*(C`interval <= 0\*(C'\fR.
+.Sp
+Basically this is a sub-second-resolution \f(CW\*(C`sleep ()\*(C'\fR.
+.Sp
+The range of the \f(CW\*(C`interval\*(C'\fR is limited \- libev only guarantees to work
+with sleep times of up to one day (\f(CW\*(C`interval <= 86400\*(C'\fR).
.IP "int ev_version_major ()" 4
.IX Item "int ev_version_major ()"
.PD 0
@@ -555,13 +561,16 @@ example) that can't properly initialise their signal masks.
.el .IP "\f(CWEVFLAG_NOSIGMASK\fR" 4
.IX Item "EVFLAG_NOSIGMASK"
When this flag is specified, then libev will avoid to modify the signal
-mask. Specifically, this means you ahve to make sure signals are unblocked
+mask. Specifically, this means you have to make sure signals are unblocked
when you want to receive them.
.Sp
This behaviour is useful when you want to do your own signal handling, or
want to handle signals only in specific threads and want to avoid libev
unblocking the signals.
.Sp
+It's also required by \s-1POSIX\s0 in a threaded program, as libev calls
+\&\f(CW\*(C`sigprocmask\*(C'\fR, whose behaviour is officially unspecified.
+.Sp
This flag's behaviour will become the default in future versions of libev.
.ie n .IP """EVBACKEND_SELECT"" (value 1, portable select backend)" 4
.el .IP "\f(CWEVBACKEND_SELECT\fR (value 1, portable select backend)" 4
@@ -600,10 +609,10 @@ This backend maps \f(CW\*(C`EV_READ\*(C'\fR to \f(CW\*(C`POLLIN | POLLERR | POLL
Use the linux-specific \fIepoll\fR\|(7) interface (for both pre\- and post\-2.6.9
kernels).
.Sp
-For few fds, this backend is a bit little slower than poll and select,
-but it scales phenomenally better. While poll and select usually scale
-like O(total_fds) where n is the total number of fds (or the highest fd),
-epoll scales either O(1) or O(active_fds).
+For few fds, this backend is a bit little slower than poll and select, but
+it scales phenomenally better. While poll and select usually scale like
+O(total_fds) where total_fds is the total number of fds (or the highest
+fd), epoll scales either O(1) or O(active_fds).
.Sp
The epoll mechanism deserves honorable mention as the most misdesigned
of the more advanced event mechanisms: mere annoyances include silently
@@ -616,19 +625,22 @@ forks then \fIboth\fR parent and child process have to recreate the epoll
set, which can take considerable time (one syscall per file descriptor)
and is of course hard to detect.
.Sp
-Epoll is also notoriously buggy \- embedding epoll fds \fIshould\fR work, but
-of course \fIdoesn't\fR, and epoll just loves to report events for totally
-\&\fIdifferent\fR file descriptors (even already closed ones, so one cannot
-even remove them from the set) than registered in the set (especially
-on \s-1SMP\s0 systems). Libev tries to counter these spurious notifications by
-employing an additional generation counter and comparing that against the
-events to filter out spurious ones, recreating the set when required. Last
+Epoll is also notoriously buggy \- embedding epoll fds \fIshould\fR work,
+but of course \fIdoesn't\fR, and epoll just loves to report events for
+totally \fIdifferent\fR file descriptors (even already closed ones, so
+one cannot even remove them from the set) than registered in the set
+(especially on \s-1SMP\s0 systems). Libev tries to counter these spurious
+notifications by employing an additional generation counter and comparing
+that against the events to filter out spurious ones, recreating the set
+when required. Epoll also erroneously rounds down timeouts, but gives you
+no way to know when and by how much, so sometimes you have to busy-wait
+because epoll returns immediately despite a nonzero timeout. And last
not least, it also refuses to work with some file descriptors which work
perfectly fine with \f(CW\*(C`select\*(C'\fR (files, many character devices...).
.Sp
-Epoll is truly the train wreck analog among event poll mechanisms,
-a frankenpoll, cobbled together in a hurry, no thought to design or
-interaction with others.
+Epoll is truly the train wreck among event poll mechanisms, a frankenpoll,
+cobbled together in a hurry, no thought to design or interaction with
+others. Oh, the pain, will it ever stop...
.Sp
While stopping, setting and starting an I/O watcher in the same iteration
will result in some caching, there is still a system call per such
@@ -716,11 +728,11 @@ hacks).
.Sp
On the negative side, the interface is \fIbizarre\fR \- so bizarre that
even sun itself gets it wrong in their code examples: The event polling
-function sometimes returning events to the caller even though an error
+function sometimes returns events to the caller even though an error
occurred, but with no indication whether it has done so or not (yes, it's
-even documented that way) \- deadly for edge-triggered interfaces where
-you absolutely have to know whether an event occurred or not because you
-have to re-arm the watcher.
+even documented that way) \- deadly for edge-triggered interfaces where you
+absolutely have to know whether an event occurred or not because you have
+to re-arm the watcher.
.Sp
Fortunately libev seems to be able to work around these idiocies.
.Sp
@@ -941,7 +953,9 @@ with something not expressible using other libev watchers (i.e. "roll your
own \f(CW\*(C`ev_run\*(C'\fR"). However, a pair of \f(CW\*(C`ev_prepare\*(C'\fR/\f(CW\*(C`ev_check\*(C'\fR watchers is
usually a better approach for this kind of thing.
.Sp
-Here are the gory details of what \f(CW\*(C`ev_run\*(C'\fR does:
+Here are the gory details of what \f(CW\*(C`ev_run\*(C'\fR does (this is for your
+understanding, not a guarantee that things will work exactly like this in
+future versions):
.Sp
.Vb 10
\& \- Increment loop depth.
@@ -987,7 +1001,7 @@ anymore.
\& ... queue jobs here, make sure they register event watchers as long
\& ... as they still have work to do (even an idle watcher will do..)
\& ev_run (my_loop, 0);
-\& ... jobs done or somebody called unloop. yeah!
+\& ... jobs done or somebody called break. yeah!
.Ve
.IP "ev_break (loop, how)" 4
.IX Item "ev_break (loop, how)"
@@ -1066,10 +1080,11 @@ overhead for the actual polling but can deliver many events at once.
By setting a higher \fIio collect interval\fR you allow libev to spend more
time collecting I/O events, so you can handle more events per iteration,
at the cost of increasing latency. Timeouts (both \f(CW\*(C`ev_periodic\*(C'\fR and
-\&\f(CW\*(C`ev_timer\*(C'\fR) will be not affected. Setting this to a non-null value will
+\&\f(CW\*(C`ev_timer\*(C'\fR) will not be affected. Setting this to a non-null value will
introduce an additional \f(CW\*(C`ev_sleep ()\*(C'\fR call into most loop iterations. The
sleep time ensures that libev will not poll for I/O events more often then
-once per this interval, on average.
+once per this interval, on average (as long as the host time resolution is
+good enough).
.Sp
Likewise, by setting a higher \fItimeout collect interval\fR you allow libev
to spend more time collecting timeouts, at the expense of increased
@@ -1131,7 +1146,7 @@ each call to a libev function.
.Sp
However, \f(CW\*(C`ev_run\*(C'\fR can run an indefinite time, so it is not feasible
to wait for it to return. One way around this is to wake up the event
-loop via \f(CW\*(C`ev_break\*(C'\fR and \f(CW\*(C`av_async_send\*(C'\fR, another way is to set these
+loop via \f(CW\*(C`ev_break\*(C'\fR and \f(CW\*(C`ev_async_send\*(C'\fR, another way is to set these
\&\fIrelease\fR and \fIacquire\fR callbacks on the loop.
.Sp
When set, then \f(CW\*(C`release\*(C'\fR will be called just before the thread is
@@ -1488,12 +1503,14 @@ transition between them will be described in more detail \- and while these
rules might look complicated, they usually do \*(L"the right thing\*(R".
.IP "initialiased" 4
.IX Item "initialiased"
-Before a watcher can be registered with the event looop it has to be
+Before a watcher can be registered with the event loop it has to be
initialised. This can be done with a call to \f(CW\*(C`ev_TYPE_init\*(C'\fR, or calls to
\&\f(CW\*(C`ev_init\*(C'\fR followed by the watcher-specific \f(CW\*(C`ev_TYPE_set\*(C'\fR function.
.Sp
-In this state it is simply some block of memory that is suitable for use
-in an event loop. It can be moved around, freed, reused etc. at will.
+In this state it is simply some block of memory that is suitable for
+use in an event loop. It can be moved around, freed, reused etc. at
+will \- as long as you either keep the memory contents intact, or call
+\&\f(CW\*(C`ev_TYPE_init\*(C'\fR again.
.IP "started/running/active" 4
.IX Item "started/running/active"
Once a watcher has been started with a call to \f(CW\*(C`ev_TYPE_start\*(C'\fR it becomes
@@ -1528,8 +1545,9 @@ of whether it was active or not, so stopping a watcher explicitly before
freeing it is often a good idea.
.Sp
While stopped (and not pending) the watcher is essentially in the
-initialised state, that is it can be reused, moved, modified in any way
-you wish.
+initialised state, that is, it can be reused, moved, modified in any way
+you wish (but when you trash the memory block, you need to \f(CW\*(C`ev_TYPE_init\*(C'\fR
+it again).
.SS "\s-1WATCHER\s0 \s-1PRIORITY\s0 \s-1MODELS\s0"
.IX Subsection "WATCHER PRIORITY MODELS"
Many event loops support \fIwatcher priorities\fR, which are usually small
@@ -1867,10 +1885,11 @@ monotonic clock option helps a lot here).
.PP
The callback is guaranteed to be invoked only \fIafter\fR its timeout has
passed (not \fIat\fR, so on systems with very low-resolution clocks this
-might introduce a small delay). If multiple timers become ready during the
-same loop iteration then the ones with earlier time-out values are invoked
-before ones of the same priority with later time-out values (but this is
-no longer true when a callback calls \f(CW\*(C`ev_run\*(C'\fR recursively).
+might introduce a small delay, see \*(L"the special problem of being too
+early\*(R", below). If multiple timers become ready during the same loop
+iteration then the ones with earlier time-out values are invoked before
+ones of the same priority with later time-out values (but this is no
+longer true when a callback calls \f(CW\*(C`ev_run\*(C'\fR recursively).
.PP
\fIBe smart about timeouts\fR
.IX Subsection "Be smart about timeouts"
@@ -1962,68 +1981,84 @@ In this case, it would be more efficient to leave the \f(CW\*(C`ev_timer\*(C'\fR
but remember the time of last activity, and check for a real timeout only
within the callback:
.Sp
-.Vb 1
+.Vb 3
+\& ev_tstamp timeout = 60.;
\& ev_tstamp last_activity; // time of last activity
+\& ev_timer timer;
\&
\& static void
\& callback (EV_P_ ev_timer *w, int revents)
\& {
-\& ev_tstamp now = ev_now (EV_A);
-\& ev_tstamp timeout = last_activity + 60.;
+\& // calculate when the timeout would happen
+\& ev_tstamp after = last_activity \- ev_now (EV_A) + timeout;
\&
-\& // if last_activity + 60. is older than now, we did time out
-\& if (timeout < now)
+\& // if negative, it means we the timeout already occured
+\& if (after < 0.)
\& {
\& // timeout occurred, take action
\& }
\& else
\& {
-\& // callback was invoked, but there was some activity, re\-arm
-\& // the watcher to fire in last_activity + 60, which is
-\& // guaranteed to be in the future, so "again" is positive:
-\& w\->repeat = timeout \- now;
-\& ev_timer_again (EV_A_ w);
+\& // callback was invoked, but there was some recent
+\& // activity. simply restart the timer to time out
+\& // after "after" seconds, which is the earliest time
+\& // the timeout can occur.
+\& ev_timer_set (w, after, 0.);
+\& ev_timer_start (EV_A_ w);
\& }
\& }
.Ve
.Sp
-To summarise the callback: first calculate the real timeout (defined
-as \*(L"60 seconds after the last activity\*(R"), then check if that time has
-been reached, which means something \fIdid\fR, in fact, time out. Otherwise
-the callback was invoked too early (\f(CW\*(C`timeout\*(C'\fR is in the future), so
-re-schedule the timer to fire at that future time, to see if maybe we have
-a timeout then.
+To summarise the callback: first calculate in how many seconds the
+timeout will occur (by calculating the absolute time when it would occur,
+\&\f(CW\*(C`last_activity + timeout\*(C'\fR, and subtracting the current time, \f(CW\*(C`ev_now
+(EV_A)\*(C'\fR from that).
+.Sp
+If this value is negative, then we are already past the timeout, i.e. we
+timed out, and need to do whatever is needed in this case.
.Sp
-Note how \f(CW\*(C`ev_timer_again\*(C'\fR is used, taking advantage of the
-\&\f(CW\*(C`ev_timer_again\*(C'\fR optimisation when the timer is already running.
+Otherwise, we now the earliest time at which the timeout would trigger,
+and simply start the timer with this timeout value.
+.Sp
+In other words, each time the callback is invoked it will check whether
+the timeout cocured. If not, it will simply reschedule itself to check
+again at the earliest time it could time out. Rinse. Repeat.
.Sp
This scheme causes more callback invocations (about one every 60 seconds
minus half the average time between activity), but virtually no calls to
libev to change the timeout.
.Sp
-To start the timer, simply initialise the watcher and set \f(CW\*(C`last_activity\*(C'\fR
-to the current time (meaning we just have some activity :), then call the
-callback, which will \*(L"do the right thing\*(R" and start the timer:
+To start the machinery, simply initialise the watcher and set
+\&\f(CW\*(C`last_activity\*(C'\fR to the current time (meaning there was some activity just
+now), then call the callback, which will \*(L"do the right thing\*(R" and start
+the timer:
.Sp
.Vb 3
-\& ev_init (timer, callback);
-\& last_activity = ev_now (loop);
-\& callback (loop, timer, EV_TIMER);
+\& last_activity = ev_now (EV_A);
+\& ev_init (&timer, callback);
+\& callback (EV_A_ &timer, 0);
.Ve
.Sp
-And when there is some activity, simply store the current time in
+When there is some activity, simply store the current time in
\&\f(CW\*(C`last_activity\*(C'\fR, no libev calls at all:
.Sp
-.Vb 1
-\& last_activity = ev_now (loop);
+.Vb 2
+\& if (activity detected)
+\& last_activity = ev_now (EV_A);
+.Ve
+.Sp
+When your timeout value changes, then the timeout can be changed by simply
+providing a new value, stopping the timer and calling the callback, which
+will agaion do the right thing (for example, time out immediately :).
+.Sp
+.Vb 3
+\& timeout = new_value;
+\& ev_timer_stop (EV_A_ &timer);
+\& callback (EV_A_ &timer, 0);
.Ve
.Sp
This technique is slightly more complex, but in most cases where the
time-out is unlikely to be triggered, much more efficient.
-.Sp
-Changing the timeout is trivial as well (if it isn't hard-coded in the
-callback :) \- just change the timeout and invoke the callback, which will
-fix things for you.
.IP "4. Wee, just use a double-linked list for your timeouts." 4
.IX Item "4. Wee, just use a double-linked list for your timeouts."
If there is not one request, but many thousands (millions...), all
@@ -2057,11 +2092,49 @@ rather complicated, but extremely efficient, something that really pays
off after the first million or so of active timers, i.e. it's usually
overkill :)
.PP
+\fIThe special problem of being too early\fR
+.IX Subsection "The special problem of being too early"
+.PP
+If you ask a timer to call your callback after three seconds, then
+you expect it to be invoked after three seconds \- but of course, this
+cannot be guaranteed to infinite precision. Less obviously, it cannot be
+guaranteed to any precision by libev \- imagine somebody suspending the
+process with a \s-1STOP\s0 signal for a few hours for example.
+.PP
+So, libev tries to invoke your callback as soon as possible \fIafter\fR the
+delay has occurred, but cannot guarantee this.
+.PP
+A less obvious failure mode is calling your callback too early: many event
+loops compare timestamps with a \*(L"elapsed delay >= requested delay\*(R", but
+this can cause your callback to be invoked much earlier than you would
+expect.
+.PP
+To see why, imagine a system with a clock that only offers full second
+resolution (think windows if you can't come up with a broken enough \s-1OS\s0
+yourself). If you schedule a one-second timer at the time 500.9, then the
+event loop will schedule your timeout to elapse at a system time of 500
+(500.9 truncated to the resolution) + 1, or 501.
+.PP
+If an event library looks at the timeout 0.1s later, it will see \*(L"501 >=
+501\*(R" and invoke the callback 0.1s after it was started, even though a
+one-second delay was requested \- this is being \*(L"too early\*(R", despite best
+intentions.
+.PP
+This is the reason why libev will never invoke the callback if the elapsed
+delay equals the requested delay, but only when the elapsed delay is
+larger than the requested delay. In the example above, libev would only invoke
+the callback at system time 502, or 1.1s after the timer was started.
+.PP
+So, while libev cannot guarantee that your callback will be invoked
+exactly when requested, it \fIcan\fR and \fIdoes\fR guarantee that the requested
+delay has actually elapsed, or in other words, it always errs on the \*(L"too
+late\*(R" side of things.
+.PP
\fIThe special problem of time updates\fR
.IX Subsection "The special problem of time updates"
.PP
-Establishing the current time is a costly operation (it usually takes at
-least two system calls): \s-1EV\s0 therefore updates its idea of the current
+Establishing the current time is a costly operation (it usually takes
+at least one system call): \s-1EV\s0 therefore updates its idea of the current
time only before and after \f(CW\*(C`ev_run\*(C'\fR collects new events, which causes a
growing difference between \f(CW\*(C`ev_now ()\*(C'\fR and \f(CW\*(C`ev_time ()\*(C'\fR when handling
lots of events in one iteration.
@@ -2080,6 +2153,40 @@ If the event loop is suspended for a long time, you can also force an
update of the time returned by \f(CW\*(C`ev_now ()\*(C'\fR by calling \f(CW\*(C`ev_now_update
()\*(C'\fR.
.PP
+\fIThe special problem of unsynchronised clocks\fR
+.IX Subsection "The special problem of unsynchronised clocks"
+.PP
+Modern systems have a variety of clocks \- libev itself uses the normal
+\&\*(L"wall clock\*(R" clock and, if available, the monotonic clock (to avoid time
+jumps).
+.PP
+Neither of these clocks is synchronised with each other or any other clock
+on the system, so \f(CW\*(C`ev_time ()\*(C'\fR might return a considerably different time
+than \f(CW\*(C`gettimeofday ()\*(C'\fR or \f(CW\*(C`time ()\*(C'\fR. On a GNU/Linux system, for example,
+a call to \f(CW\*(C`gettimeofday\*(C'\fR might return a second count that is one higher
+than a directly following call to \f(CW\*(C`time\*(C'\fR.
+.PP
+The moral of this is to only compare libev-related timestamps with
+\&\f(CW\*(C`ev_time ()\*(C'\fR and \f(CW\*(C`ev_now ()\*(C'\fR, at least if you want better precision than
+a second or so.
+.PP
+One more problem arises due to this lack of synchronisation: if libev uses
+the system monotonic clock and you compare timestamps from \f(CW\*(C`ev_time\*(C'\fR
+or \f(CW\*(C`ev_now\*(C'\fR from when you started your timer and when your callback is
+invoked, you will find that sometimes the callback is a bit \*(L"early\*(R".
+.PP
+This is because \f(CW\*(C`ev_timer\*(C'\fRs work in real time, not wall clock time, so
+libev makes sure your callback is not invoked before the delay happened,
+\&\fImeasured according to the real time\fR, not the system clock.
+.PP
+If your timeouts are based on a physical timescale (e.g. \*(L"time out this
+connection after 100 seconds\*(R") then this shouldn't bother you as it is
+exactly the right behaviour.
+.PP
+If you want to compare wall clock/system timestamps to your timers, then
+you need to use \f(CW\*(C`ev_periodic\*(C'\fRs, as these are based on the wall clock
+time, where your comparisons will always generate correct results.
+.PP
\fIThe special problems of suspended animation\fR
.IX Subsection "The special problems of suspended animation"
.PP
@@ -2132,18 +2239,28 @@ keep up with the timer (because it takes longer than those 10 seconds to
do stuff) the timer will not fire more than once per event loop iteration.
.IP "ev_timer_again (loop, ev_timer *)" 4
.IX Item "ev_timer_again (loop, ev_timer *)"
-This will act as if the timer timed out and restart it again if it is
-repeating. The exact semantics are:
-.Sp
-If the timer is pending, its pending status is cleared.
-.Sp
-If the timer is started but non-repeating, stop it (as if it timed out).
+This will act as if the timer timed out, and restarts it again if it is
+repeating. It basically works like calling \f(CW\*(C`ev_timer_stop\*(C'\fR, updating the
+timeout to the \f(CW\*(C`repeat\*(C'\fR value and calling \f(CW\*(C`ev_timer_start\*(C'\fR.
.Sp
-If the timer is repeating, either start it if necessary (with the
-\&\f(CW\*(C`repeat\*(C'\fR value), or reset the running timer to the \f(CW\*(C`repeat\*(C'\fR value.
+The exact semantics are as in the following rules, all of which will be
+applied to the watcher:
+.RS 4
+.IP "If the timer is pending, the pending status is always cleared." 4
+.IX Item "If the timer is pending, the pending status is always cleared."
+.PD 0
+.IP "If the timer is started but non-repeating, stop it (as if it timed out, without invoking it)." 4
+.IX Item "If the timer is started but non-repeating, stop it (as if it timed out, without invoking it)."
+.ie n .IP "If the timer is repeating, make the ""repeat"" value the new timeout and start the timer, if necessary." 4
+.el .IP "If the timer is repeating, make the \f(CWrepeat\fR value the new timeout and start the timer, if necessary." 4
+.IX Item "If the timer is repeating, make the repeat value the new timeout and start the timer, if necessary."
+.RE
+.RS 4
+.PD
.Sp
This sounds a bit complicated, see \*(L"Be smart about timeouts\*(R", above, for a
usage example.
+.RE
.IP "ev_tstamp ev_timer_remaining (loop, ev_timer *)" 4
.IX Item "ev_tstamp ev_timer_remaining (loop, ev_timer *)"
Returns the remaining time until a timer fires. If the timer is active,
@@ -2273,9 +2390,12 @@ Another way to think about it (for the mathematically inclined) is that
\&\f(CW\*(C`ev_periodic\*(C'\fR will try to run the callback in this mode at the next possible
time where \f(CW\*(C`time = offset (mod interval)\*(C'\fR, regardless of any time jumps.
.Sp
-For numerical stability it is preferable that the \f(CW\*(C`offset\*(C'\fR value is near
-\&\f(CW\*(C`ev_now ()\*(C'\fR (the current time), but there is no range requirement for
-this value, and in fact is often specified as zero.
+The \f(CW\*(C`interval\*(C'\fR \fI\s-1MUST\s0\fR be positive, and for numerical stability, the
+interval value should be higher than \f(CW\*(C`1/8192\*(C'\fR (which is around 100
+microseconds) and \f(CW\*(C`offset\*(C'\fR should be higher than \f(CW0\fR and should have
+at most a similar magnitude as the current time (say, within a factor of
+ten). Typical values for offset are, in fact, \f(CW0\fR or something between
+\&\f(CW0\fR and \f(CW\*(C`interval\*(C'\fR, which is also the recommended range.
.Sp
Note also that there is an upper limit to how often a timer can fire (\s-1CPU\s0
speed for example), so if \f(CW\*(C`interval\*(C'\fR is very small then timing stability
@@ -2431,7 +2551,8 @@ and unblock them in an \f(CW\*(C`ev_prepare\*(C'\fR watcher.
Both the signal mask (\f(CW\*(C`sigprocmask\*(C'\fR) and the signal disposition
(\f(CW\*(C`sigaction\*(C'\fR) are unspecified after starting a signal watcher (and after
stopping it again), that is, libev might or might not block the signal,
-and might or might not set or restore the installed signal handler.
+and might or might not set or restore the installed signal handler (but
+see \f(CW\*(C`EVFLAG_NOSIGMASK\*(C'\fR).
.PP
While this does not matter for the signal disposition (libev never
sets signals to \f(CW\*(C`SIG_IGN\*(C'\fR, so handlers will be reset to \f(CW\*(C`SIG_DFL\*(C'\fR on
@@ -3309,7 +3430,7 @@ cleanup functions are called.
.ie n .SS """ev_async"" \- how to wake up an event loop"
.el .SS "\f(CWev_async\fP \- how to wake up an event loop"
.IX Subsection "ev_async - how to wake up an event loop"
-In general, you cannot use an \f(CW\*(C`ev_run\*(C'\fR from multiple threads or other
+In general, you cannot use an \f(CW\*(C`ev_loop\*(C'\fR from multiple threads or other
asynchronous sources such as signal handlers (as opposed to multiple event
loops \- those are of course safe to use in different threads).
.PP
@@ -3326,9 +3447,6 @@ of \*(L"global async watchers\*(R" by using a watcher on an otherwise unused
signal, and \f(CW\*(C`ev_feed_signal\*(C'\fR to signal this watcher from another thread,
even without knowing which loop owns the signal.
.PP
-Unlike \f(CW\*(C`ev_signal\*(C'\fR watchers, \f(CW\*(C`ev_async\*(C'\fR works with any event loop, not
-just the default loop.
-.PP
\fIQueueing\fR
.IX Subsection "Queueing"
.PP
@@ -3424,19 +3542,24 @@ trust me.
.IP "ev_async_send (loop, ev_async *)" 4
.IX Item "ev_async_send (loop, ev_async *)"
Sends/signals/activates the given \f(CW\*(C`ev_async\*(C'\fR watcher, that is, feeds
-an \f(CW\*(C`EV_ASYNC\*(C'\fR event on the watcher into the event loop. Unlike
-\&\f(CW\*(C`ev_feed_event\*(C'\fR, this call is safe to do from other threads, signal or
-similar contexts (see the discussion of \f(CW\*(C`EV_ATOMIC_T\*(C'\fR in the embedding
-section below on what exactly this means).
+an \f(CW\*(C`EV_ASYNC\*(C'\fR event on the watcher into the event loop, and instantly
+returns.
.Sp
-Note that, as with other watchers in libev, multiple events might get
-compressed into a single callback invocation (another way to look at this
-is that \f(CW\*(C`ev_async\*(C'\fR watchers are level-triggered, set on \f(CW\*(C`ev_async_send\*(C'\fR,
-reset when the event loop detects that).
+Unlike \f(CW\*(C`ev_feed_event\*(C'\fR, this call is safe to do from other threads,
+signal or similar contexts (see the discussion of \f(CW\*(C`EV_ATOMIC_T\*(C'\fR in the
+embedding section below on what exactly this means).
.Sp
-This call incurs the overhead of a system call only once per event loop
-iteration, so while the overhead might be noticeable, it doesn't apply to
-repeated calls to \f(CW\*(C`ev_async_send\*(C'\fR for the same event loop.
+Note that, as with other watchers in libev, multiple events might get
+compressed into a single callback invocation (another way to look at
+this is that \f(CW\*(C`ev_async\*(C'\fR watchers are level-triggered: they are set on
+\&\f(CW\*(C`ev_async_send\*(C'\fR, reset when the event loop detects that).
+.Sp
+This call incurs the overhead of at most one extra system call per event
+loop iteration, if the event loop is blocked, and no syscall at all if
+the event loop (or your program) is processing events. That means that
+repeated calls are basically free (there is no need to avoid calls for
+performance reasons) and that the overhead becomes smaller (typically
+zero) under load.
.IP "bool = ev_async_pending (ev_async *)" 4
.IX Item "bool = ev_async_pending (ev_async *)"
Returns a non-zero value when \f(CW\*(C`ev_async_send\*(C'\fR has been called on the
@@ -3494,7 +3617,7 @@ Example: wait up to ten seconds for data to appear on \s-1STDIN_FILENO\s0.
.IP "ev_feed_fd_event (loop, int fd, int revents)" 4
.IX Item "ev_feed_fd_event (loop, int fd, int revents)"
Feed an event on the given fd, as if a file descriptor backend detected
-the given events it.
+the given events.
.IP "ev_feed_signal_event (loop, int signum)" 4
.IX Item "ev_feed_signal_event (loop, int signum)"
Feed an event as if the given signal occurred. See also \f(CW\*(C`ev_feed_signal\*(C'\fR,
@@ -3578,6 +3701,49 @@ real programmers):
\& (((char *)w) \- offsetof (struct my_biggy, t2));
\& }
.Ve
+.SS "\s-1AVOIDING\s0 \s-1FINISHING\s0 \s-1BEFORE\s0 \s-1RETURNING\s0"
+.IX Subsection "AVOIDING FINISHING BEFORE RETURNING"
+Often you have structures like this in event-based programs:
+.PP
+.Vb 4
+\& callback ()
+\& {
+\& free (request);
+\& }
+\&
+\& request = start_new_request (..., callback);
+.Ve
+.PP
+The intent is to start some \*(L"lengthy\*(R" operation. The \f(CW\*(C`request\*(C'\fR could be
+used to cancel the operation, or do other things with it.
+.PP
+It's not uncommon to have code paths in \f(CW\*(C`start_new_request\*(C'\fR that
+immediately invoke the callback, for example, to report errors. Or you add
+some caching layer that finds that it can skip the lengthy aspects of the
+operation and simply invoke the callback with the result.
+.PP
+The problem here is that this will happen \fIbefore\fR \f(CW\*(C`start_new_request\*(C'\fR
+has returned, so \f(CW\*(C`request\*(C'\fR is not set.
+.PP
+Even if you pass the request by some safer means to the callback, you
+might want to do something to the request after starting it, such as
+canceling it, which probably isn't working so well when the callback has
+already been invoked.
+.PP
+A common way around all these issues is to make sure that
+\&\f(CW\*(C`start_new_request\*(C'\fR \fIalways\fR returns before the callback is invoked. If
+\&\f(CW\*(C`start_new_request\*(C'\fR immediately knows the result, it can artificially
+delay invoking the callback by e.g. using a \f(CW\*(C`prepare\*(C'\fR or \f(CW\*(C`idle\*(C'\fR watcher
+for example, or more sneakily, by reusing an existing (stopped) watcher
+and pushing it into the pending queue:
+.PP
+.Vb 2
+\& ev_set_cb (watcher, callback);
+\& ev_feed_event (EV_A_ watcher, 0);
+.Ve
+.PP
+This way, \f(CW\*(C`start_new_request\*(C'\fR can safely return before the callback is
+invoked, while not delaying callback invocation too much.
.SS "\s-1MODEL/NESTED\s0 \s-1EVENT\s0 \s-1LOOP\s0 \s-1INVOCATIONS\s0 \s-1AND\s0 \s-1EXIT\s0 \s-1CONDITIONS\s0"
.IX Subsection "MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS"
Often (especially in \s-1GUI\s0 toolkits) there are places where you have
@@ -3601,7 +3767,7 @@ triggered, using \f(CW\*(C`EVRUN_ONCE\*(C'\fR:
\& while (!exit_main_loop)
\& ev_run (EV_DEFAULT_ EVRUN_ONCE);
\&
-\& // in a model watcher
+\& // in a modal watcher
\& int exit_nested_loop = 0;
\&
\& while (!exit_nested_loop)
@@ -3660,7 +3826,7 @@ First, you need to associate some data with the event loop:
\& ev_set_invoke_pending_cb (EV_A_ l_invoke);
\& ev_set_loop_release_cb (EV_A_ l_release, l_acquire);
\&
-\& // then create the thread running ev_loop
+\& // then create the thread running ev_run
\& pthread_create (&u\->tid, 0, l_run, EV_A);
\& }
.Ve
@@ -3810,7 +3976,7 @@ called):
.PP
That basically suspends the coroutine inside \f(CW\*(C`wait_for_event\*(C'\fR and
continues the libev coroutine, which, when appropriate, switches back to
-this or any other coroutine. I am sure if you sue this your own :)
+this or any other coroutine.
.PP
You can do similar tricks if you have, say, threads with an event queue \-
instead of storing a coroutine, you store the queue object and instead of
@@ -3908,7 +4074,7 @@ Aliases to the same types/functions as with the \f(CW\*(C`ev_\*(C'\fR prefix.
For each \f(CW\*(C`ev_TYPE\*(C'\fR watcher in \fIev.h\fR there is a corresponding class of
the same name in the \f(CW\*(C`ev\*(C'\fR namespace, with the exception of \f(CW\*(C`ev_signal\*(C'\fR
which is called \f(CW\*(C`ev::sig\*(C'\fR to avoid clashes with the \f(CW\*(C`signal\*(C'\fR macro
-defines by many implementations.
+defined by many implementations.
.Sp
All of those classes have these methods:
.RS 4
@@ -4049,7 +4215,7 @@ watchers in the constructor.
\& class myclass
\& {
\& ev::io io ; void io_cb (ev::io &w, int revents);
-\& ev::io2 io2 ; void io2_cb (ev::io &w, int revents);
+\& ev::io io2 ; void io2_cb (ev::io &w, int revents);
\& ev::idle idle; void idle_cb (ev::idle &w, int revents);
\&
\& myclass (int fd)
@@ -4098,20 +4264,20 @@ makes rev work even on mingw.
.IP "Haskell" 4
.IX Item "Haskell"
A haskell binding to libev is available at
-<http://hackage.haskell.org/cgi\-bin/hackage\-scripts/package/hlibev>.
+http://hackage.haskell.org/cgi\-bin/hackage\-scripts/package/hlibev <http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hlibev>.
.IP "D" 4
.IX Item "D"
Leandro Lucarella has written a D language binding (\fIev.d\fR) for libev, to
-be found at <http://proj.llucax.com.ar/wiki/evd>.
+be found at <http://www.llucax.com.ar/proj/ev.d/index.html>.
.IP "Ocaml" 4
.IX Item "Ocaml"
Erkki Seppala has written Ocaml bindings for libev, to be found at
-<http://modeemi.cs.tut.fi/~flux/software/ocaml\-ev/>.
+http://modeemi.cs.tut.fi/~flux/software/ocaml\-ev/ <http://modeemi.cs.tut.fi/~flux/software/ocaml-ev/>.
.IP "Lua" 4
.IX Item "Lua"
Brian Maher has written a partial interface to libev for lua (at the
time of this writing, only \f(CW\*(C`ev_io\*(C'\fR and \f(CW\*(C`ev_timer\*(C'\fR), to be found at
-<http://github.com/brimworks/lua\-ev>.
+http://github.com/brimworks/lua\-ev <http://github.com/brimworks/lua-ev>.
.SH "MACRO MAGIC"
.IX Header "MACRO MAGIC"
Libev can be compiled with a variety of options, the most fundamental
@@ -4156,7 +4322,11 @@ suitable for use with \f(CW\*(C`EV_A\*(C'\fR.
.el .IP "\f(CWEV_DEFAULT\fR, \f(CWEV_DEFAULT_\fR" 4
.IX Item "EV_DEFAULT, EV_DEFAULT_"
Similar to the other two macros, this gives you the value of the default
-loop, if multiple loops are supported (\*(L"ev loop default\*(R").
+loop, if multiple loops are supported (\*(L"ev loop default\*(R"). The default loop
+will be initialised if it isn't already initialised.
+.Sp
+For non-multiplicity builds, these macros do nothing, so you always have
+to initialise the loop somewhere.
.ie n .IP """EV_DEFAULT_UC"", ""EV_DEFAULT_UC_""" 4
.el .IP "\f(CWEV_DEFAULT_UC\fR, \f(CWEV_DEFAULT_UC_\fR" 4
.IX Item "EV_DEFAULT_UC, EV_DEFAULT_UC_"
@@ -4321,6 +4491,14 @@ supported). It will also not define any of the structs usually found in
.Sp
In standalone mode, libev will still try to automatically deduce the
configuration, but has to be more conservative.
+.IP "\s-1EV_USE_FLOOR\s0" 4
+.IX Item "EV_USE_FLOOR"
+If defined to be \f(CW1\fR, libev will use the \f(CW\*(C`floor ()\*(C'\fR function for its
+periodic reschedule calculations, otherwise libev will fall back on a
+portable (slower) implementation. If you enable this, you usually have to
+link against libm or something equivalent. Enabling this when the \f(CW\*(C`floor\*(C'\fR
+function is not available will fail, so the safe default is to not enable
+this.
.IP "\s-1EV_USE_MONOTONIC\s0" 4
.IX Item "EV_USE_MONOTONIC"
If defined to be \f(CW1\fR, libev will try to detect the availability of the
@@ -4442,16 +4620,30 @@ If defined to be \f(CW1\fR, libev will compile in support for the Linux inotify
interface to speed up \f(CW\*(C`ev_stat\*(C'\fR watchers. Its actual availability will
be detected at runtime. If undefined, it will be enabled if the headers
indicate GNU/Linux + Glibc 2.4 or newer, otherwise disabled.
+.IP "\s-1EV_NO_SMP\s0" 4
+.IX Item "EV_NO_SMP"
+If defined to be \f(CW1\fR, libev will assume that memory is always coherent
+between threads, that is, threads can be used, but threads never run on
+different cpus (or different cpu cores). This reduces dependencies
+and makes libev faster.
+.IP "\s-1EV_NO_THREADS\s0" 4
+.IX Item "EV_NO_THREADS"
+If defined to be \f(CW1\fR, libev will assume that it will never be called
+from different threads, which is a stronger assumption than \f(CW\*(C`EV_NO_SMP\*(C'\fR,
+above. This reduces dependencies and makes libev faster.
.IP "\s-1EV_ATOMIC_T\s0" 4
.IX Item "EV_ATOMIC_T"
Libev requires an integer type (suitable for storing \f(CW0\fR or \f(CW1\fR) whose
-access is atomic with respect to other threads or signal contexts. No such
-type is easily found in the C language, so you can provide your own type
-that you know is safe for your purposes. It is used both for signal handler \*(L"locking\*(R"
-as well as for signal and thread safety in \f(CW\*(C`ev_async\*(C'\fR watchers.
+access is atomic and serialised with respect to other threads or signal
+contexts. No such type is easily found in the C language, so you can
+provide your own type that you know is safe for your purposes. It is used
+both for signal handler \*(L"locking\*(R" as well as for signal and thread safety
+in \f(CW\*(C`ev_async\*(C'\fR watchers.
.Sp
In the absence of this define, libev will use \f(CW\*(C`sig_atomic_t volatile\*(C'\fR
-(from \fIsignal.h\fR), which is usually good enough on most platforms.
+(from \fIsignal.h\fR), which is usually good enough on most platforms,
+although strictly speaking using a type that also implies a memory fence
+is required.
.IP "\s-1EV_H\s0 (h)" 4
.IX Item "EV_H (h)"
The name of the \fIev.h\fR header file used to include it. The default if
@@ -4479,6 +4671,10 @@ will have the \f(CW\*(C`struct ev_loop *\*(C'\fR as first argument, and you can
additional independent event loops. Otherwise there will be no support
for multiple event loops and there is no first event loop pointer
argument. Instead, all functions act on the single default loop.
+.Sp
+Note that \f(CW\*(C`EV_DEFAULT\*(C'\fR and \f(CW\*(C`EV_DEFAULT_\*(C'\fR will no longer provide a
+default loop when multiplicity is switched off \- you always have to
+initialise the loop manually in this case.
.IP "\s-1EV_MINPRI\s0" 4
.IX Item "EV_MINPRI"
.PD 0
@@ -4585,6 +4781,19 @@ when you use \f(CW\*(C`\-Wl,\-\-gc\-sections \-ffunction\-sections\*(C'\fR) func
your program might be left out as well \- a binary starting a timer and an
I/O watcher then might come out at only 5Kb.
.RE
+.IP "\s-1EV_API_STATIC\s0" 4
+.IX Item "EV_API_STATIC"
+If this symbol is defined (by default it is not), then all identifiers
+will have static linkage. This means that libev will not export any
+identifiers, and you cannot link against libev anymore. This can be useful
+when you embed libev, only want to use libev functions in a single file,
+and do not want its identifiers to be visible.
+.Sp
+To use this, define \f(CW\*(C`EV_API_STATIC\*(C'\fR and include \fIev.c\fR in the file that
+wants to use libev.
+.Sp
+This option only works when libev is compiled with a C compiler, as \*(C+
+doesn't support the required declaration syntax.
.IP "\s-1EV_AVOID_STDIO\s0" 4
.IX Item "EV_AVOID_STDIO"
If this is set to \f(CW1\fR at compiletime, then libev will avoid using stdio
@@ -4971,7 +5180,7 @@ model. Libev still offers limited functionality on this platform in
the form of the \f(CW\*(C`EVBACKEND_SELECT\*(C'\fR backend, and only supports socket
descriptors. This only applies when using Win32 natively, not when using
e.g. cygwin. Actually, it only applies to the microsofts own compilers,
-as every compielr comes with a slightly differently broken/incompatible
+as every compiler comes with a slightly differently broken/incompatible
environment.
.PP
Lifting these limitations would basically require the full
@@ -5117,8 +5326,12 @@ The type \f(CW\*(C`double\*(C'\fR is used to represent timestamps. It is require
have at least 51 bits of mantissa (and 9 bits of exponent), which is
good enough for at least into the year 4000 with millisecond accuracy
(the design goal for libev). This requirement is overfulfilled by
-implementations using \s-1IEEE\s0 754, which is basically all existing ones. With
-\&\s-1IEEE\s0 754 doubles, you get microsecond accuracy until at least 2200.
+implementations using \s-1IEEE\s0 754, which is basically all existing ones.
+.Sp
+With \s-1IEEE\s0 754 doubles, you get microsecond accuracy until at least the
+year 2255 (and millisecond accuracy till the year 287396 \- by then, libev
+is either obsolete or somebody patched it to use \f(CW\*(C`long double\*(C'\fR or
+something like that, just kidding).
.PP
If you know of other additional requirements drop me a note.
.SH "ALGORITHMIC COMPLEXITIES"
@@ -5182,8 +5395,9 @@ watchers becomes O(1) with respect to priority handling.
.IX Item "Processing signals: O(max_signal_number)"
.PD
Sending involves a system call \fIiff\fR there were no other \f(CW\*(C`ev_async_send\*(C'\fR
-calls in the current loop iteration. Checking for async and signal events
-involves iterating over all running async watchers or all signal numbers.
+calls in the current loop iteration and the loop is currently
+blocked. Checking for async and signal events involves iterating over all
+running async watchers or all signal numbers.
.SH "PORTING FROM LIBEV 3.X TO 4.X"
.IX Header "PORTING FROM LIBEV 3.X TO 4.X"
The major version 4 introduced some incompatible changes to the \s-1API\s0.
@@ -5290,7 +5504,7 @@ The physical time that is observed. It is apparently strictly monotonic :)
.IP "wall-clock time" 4
.IX Item "wall-clock time"
The time and date as shown on clocks. Unlike real time, it can actually
-be wrong and jump forwards and backwards, e.g. when the you adjust your
+be wrong and jump forwards and backwards, e.g. when you adjust your
clock.
.IP "watcher" 4
.IX Item "watcher"
@@ -5299,4 +5513,4 @@ to be started (attached to an event loop) before they can receive events.
.SH "AUTHOR"
.IX Header "AUTHOR"
Marc Lehmann <libev@schmorp.de>, with repeated corrections by Mikael
-Magnusson and Emanuele Giaquinta.
+Magnusson and Emanuele Giaquinta, and minor corrections by many others.
diff --git a/libev/ev.c b/libev/ev.c
index 1a8b319..fe1b6ac 100644
--- a/libev/ev.c
+++ b/libev/ev.c
@@ -6,14 +6,14 @@
*
* 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
@@ -45,6 +45,12 @@
# include "config.h"
# endif
+#if HAVE_FLOOR
+# ifndef EV_USE_FLOOR
+# define EV_USE_FLOOR 1
+# endif
+#endif
+
# if HAVE_CLOCK_SYSCALL
# ifndef EV_USE_CLOCK_SYSCALL
# define EV_USE_CLOCK_SYSCALL 1
@@ -158,7 +164,6 @@
#endif
-#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
@@ -180,7 +185,16 @@
# include "ev.h"
#endif
-EV_CPP(extern "C" {)
+#if EV_NO_THREADS
+# undef EV_NO_SMP
+# define EV_NO_SMP 1
+# undef ECB_NO_THREADS
+# define ECB_NO_THREADS 1
+#endif
+#if EV_NO_SMP
+# undef EV_NO_SMP
+# define ECB_NO_SMP 1
+#endif
#ifndef _WIN32
# include <sys/time.h>
@@ -234,6 +248,10 @@ EV_CPP(extern "C" {)
# define EV_NSIG 65
#endif
+#ifndef EV_USE_FLOOR
+# define EV_USE_FLOOR 0
+#endif
+
#ifndef EV_USE_CLOCK_SYSCALL
# if __linux && __GLIBC__ >= 2
# define EV_USE_CLOCK_SYSCALL EV_FEATURE_OS
@@ -378,7 +396,8 @@ EV_CPP(extern "C" {)
#endif
#if !EV_USE_NANOSLEEP
-# ifndef _WIN32
+/* hp-ux has it in sys/time.h, which we unconditionally include above */
+# if !defined(_WIN32) && !defined(__hpux)
# include <sys/select.h>
# endif
#endif
@@ -444,14 +463,11 @@ struct signalfd_siginfo
#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 is used to work around floating point rounding problems.
* This value is good at least till the year 4000.
- * Better solutions welcome.
*/
-#define TIME_EPSILON 0.0001220703125 /* 1/8192 */
+#define MIN_INTERVAL 0.0001220703125 /* 1/2**13, good till 4000 */
+/*#define MIN_INTERVAL 0.00000095367431640625 /* 1/2**20, good till 2200 */
#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) */
@@ -459,23 +475,486 @@ struct signalfd_siginfo
#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))
+/* the following is ecb.h embedded into libev - use update_ev_c to update from an external copy */
+/* ECB.H BEGIN */
+/*
+ * libecb - http://software.schmorp.de/pkg/libecb
+ *
+ * Copyright (©) 2009-2012 Marc Alexander Lehmann <libecb@schmorp.de>
+ * Copyright (©) 2011 Emanuele Giaquinta
+ * 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.
+ */
+
+#ifndef ECB_H
+#define ECB_H
+
+#ifdef _WIN32
+ typedef signed char int8_t;
+ typedef unsigned char uint8_t;
+ typedef signed short int16_t;
+ typedef unsigned short uint16_t;
+ typedef signed int int32_t;
+ typedef unsigned int uint32_t;
+ #if __GNUC__
+ typedef signed long long int64_t;
+ typedef unsigned long long uint64_t;
+ #else /* _MSC_VER || __BORLANDC__ */
+ typedef signed __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+ #endif
#else
-# define expect(expr,value) (expr)
-# define noinline
-# if __STDC_VERSION__ < 199901L && __GNUC__ < 2
-# define inline
-# endif
+ #include <inttypes.h>
+#endif
+
+/* many compilers define _GNUC_ to some versions but then only implement
+ * what their idiot authors think are the "more important" extensions,
+ * causing enormous grief in return for some better fake benchmark numbers.
+ * or so.
+ * we try to detect these and simply assume they are not gcc - if they have
+ * an issue with that they should have done it right in the first place.
+ */
+#ifndef ECB_GCC_VERSION
+ #if !defined(__GNUC_MINOR__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__llvm__) || defined(__clang__)
+ #define ECB_GCC_VERSION(major,minor) 0
+ #else
+ #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+ #endif
+#endif
+
+/*****************************************************************************/
+
+/* ECB_NO_THREADS - ecb is not used by multiple threads, ever */
+/* ECB_NO_SMP - ecb might be used in multiple threads, but only on a single cpu */
+
+#if ECB_NO_THREADS
+# define ECB_NO_SMP 1
+#endif
+
+#if ECB_NO_THREADS || ECB_NO_SMP
+ #define ECB_MEMORY_FENCE do { } while (0)
+#endif
+
+#ifndef ECB_MEMORY_FENCE
+ #if ECB_GCC_VERSION(2,5) || defined(__INTEL_COMPILER) || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
+ #if __i386 || __i386__
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("lock; orb $0, -1(%%esp)" : : : "memory")
+ #define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE /* non-lock xchg might be enough */
+ #define ECB_MEMORY_FENCE_RELEASE do { } while (0) /* unlikely to change in future cpus */
+ #elif __amd64 || __amd64__ || __x86_64 || __x86_64__
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory")
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("lfence" : : : "memory")
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("sfence") /* play safe - not needed in any current cpu */
+ #elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory")
+ #elif defined(__ARM_ARCH_6__ ) || defined(__ARM_ARCH_6J__ ) \
+ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory")
+ #elif defined(__ARM_ARCH_7__ ) || defined(__ARM_ARCH_7A__ ) \
+ || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__ )
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory")
+ #elif __sparc || __sparc__
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad | " : : : "memory")
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory")
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore")
+ #elif defined(__s390__) || defined(__s390x__)
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("bcr 15,0" : : : "memory")
+ #endif
+ #endif
+#endif
+
+#ifndef ECB_MEMORY_FENCE
+ #if ECB_GCC_VERSION(4,4) || defined(__INTEL_COMPILER) || defined(__clang__)
+ #define ECB_MEMORY_FENCE __sync_synchronize ()
+ /*#define ECB_MEMORY_FENCE_ACQUIRE ({ char dummy = 0; __sync_lock_test_and_set (&dummy, 1); }) */
+ /*#define ECB_MEMORY_FENCE_RELEASE ({ char dummy = 1; __sync_lock_release (&dummy ); }) */
+ #elif _MSC_VER >= 1400 /* VC++ 2005 */
+ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
+ #define ECB_MEMORY_FENCE _ReadWriteBarrier ()
+ #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */
+ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier ()
+ #elif defined(_WIN32)
+ #include <WinNT.h>
+ #define ECB_MEMORY_FENCE MemoryBarrier () /* actually just xchg on x86... scary */
+ #elif __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
+ #include <mbarrier.h>
+ #define ECB_MEMORY_FENCE __machine_rw_barrier ()
+ #define ECB_MEMORY_FENCE_ACQUIRE __machine_r_barrier ()
+ #define ECB_MEMORY_FENCE_RELEASE __machine_w_barrier ()
+ #endif
+#endif
+
+#ifndef ECB_MEMORY_FENCE
+ #if !ECB_AVOID_PTHREADS
+ /*
+ * if you get undefined symbol references to pthread_mutex_lock,
+ * or failure to find pthread.h, then you should implement
+ * the ECB_MEMORY_FENCE operations for your cpu/compiler
+ * OR provide pthread.h and link against the posix thread library
+ * of your system.
+ */
+ #include <pthread.h>
+ #define ECB_NEEDS_PTHREADS 1
+ #define ECB_MEMORY_FENCE_NEEDS_PTHREADS 1
+
+ static pthread_mutex_t ecb_mf_lock = PTHREAD_MUTEX_INITIALIZER;
+ #define ECB_MEMORY_FENCE do { pthread_mutex_lock (&ecb_mf_lock); pthread_mutex_unlock (&ecb_mf_lock); } while (0)
+ #endif
+#endif
+
+#if !defined(ECB_MEMORY_FENCE_ACQUIRE) && defined(ECB_MEMORY_FENCE)
+ #define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
+#endif
+
+#if !defined(ECB_MEMORY_FENCE_RELEASE) && defined(ECB_MEMORY_FENCE)
+ #define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
+#endif
+
+/*****************************************************************************/
+
+#define ECB_C99 (__STDC_VERSION__ >= 199901L)
+
+#if __cplusplus
+ #define ecb_inline static inline
+#elif ECB_GCC_VERSION(2,5)
+ #define ecb_inline static __inline__
+#elif ECB_C99
+ #define ecb_inline static inline
+#else
+ #define ecb_inline static
+#endif
+
+#if ECB_GCC_VERSION(3,3)
+ #define ecb_restrict __restrict__
+#elif ECB_C99
+ #define ecb_restrict restrict
+#else
+ #define ecb_restrict
+#endif
+
+typedef int ecb_bool;
+
+#define ECB_CONCAT_(a, b) a ## b
+#define ECB_CONCAT(a, b) ECB_CONCAT_(a, b)
+#define ECB_STRINGIFY_(a) # a
+#define ECB_STRINGIFY(a) ECB_STRINGIFY_(a)
+
+#define ecb_function_ ecb_inline
+
+#if ECB_GCC_VERSION(3,1)
+ #define ecb_attribute(attrlist) __attribute__(attrlist)
+ #define ecb_is_constant(expr) __builtin_constant_p (expr)
+ #define ecb_expect(expr,value) __builtin_expect ((expr),(value))
+ #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality)
+#else
+ #define ecb_attribute(attrlist)
+ #define ecb_is_constant(expr) 0
+ #define ecb_expect(expr,value) (expr)
+ #define ecb_prefetch(addr,rw,locality)
+#endif
+
+/* no emulation for ecb_decltype */
+#if ECB_GCC_VERSION(4,5)
+ #define ecb_decltype(x) __decltype(x)
+#elif ECB_GCC_VERSION(3,0)
+ #define ecb_decltype(x) __typeof(x)
+#endif
+
+#define ecb_noinline ecb_attribute ((__noinline__))
+#define ecb_noreturn ecb_attribute ((__noreturn__))
+#define ecb_unused ecb_attribute ((__unused__))
+#define ecb_const ecb_attribute ((__const__))
+#define ecb_pure ecb_attribute ((__pure__))
+
+#if ECB_GCC_VERSION(4,3)
+ #define ecb_artificial ecb_attribute ((__artificial__))
+ #define ecb_hot ecb_attribute ((__hot__))
+ #define ecb_cold ecb_attribute ((__cold__))
+#else
+ #define ecb_artificial
+ #define ecb_hot
+ #define ecb_cold
+#endif
+
+/* put around conditional expressions if you are very sure that the */
+/* expression is mostly true or mostly false. note that these return */
+/* booleans, not the expression. */
+#define ecb_expect_false(expr) ecb_expect (!!(expr), 0)
+#define ecb_expect_true(expr) ecb_expect (!!(expr), 1)
+/* for compatibility to the rest of the world */
+#define ecb_likely(expr) ecb_expect_true (expr)
+#define ecb_unlikely(expr) ecb_expect_false (expr)
+
+/* count trailing zero bits and count # of one bits */
+#if ECB_GCC_VERSION(3,4)
+ /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */
+ #define ecb_ld32(x) (__builtin_clz (x) ^ 31)
+ #define ecb_ld64(x) (__builtin_clzll (x) ^ 63)
+ #define ecb_ctz32(x) __builtin_ctz (x)
+ #define ecb_ctz64(x) __builtin_ctzll (x)
+ #define ecb_popcount32(x) __builtin_popcount (x)
+ /* no popcountll */
+#else
+ ecb_function_ int ecb_ctz32 (uint32_t x) ecb_const;
+ ecb_function_ int
+ ecb_ctz32 (uint32_t x)
+ {
+ int r = 0;
+
+ x &= ~x + 1; /* this isolates the lowest bit */
+
+#if ECB_branchless_on_i386
+ r += !!(x & 0xaaaaaaaa) << 0;
+ r += !!(x & 0xcccccccc) << 1;
+ r += !!(x & 0xf0f0f0f0) << 2;
+ r += !!(x & 0xff00ff00) << 3;
+ r += !!(x & 0xffff0000) << 4;
+#else
+ if (x & 0xaaaaaaaa) r += 1;
+ if (x & 0xcccccccc) r += 2;
+ if (x & 0xf0f0f0f0) r += 4;
+ if (x & 0xff00ff00) r += 8;
+ if (x & 0xffff0000) r += 16;
+#endif
+
+ return r;
+ }
+
+ ecb_function_ int ecb_ctz64 (uint64_t x) ecb_const;
+ ecb_function_ int
+ ecb_ctz64 (uint64_t x)
+ {
+ int shift = x & 0xffffffffU ? 0 : 32;
+ return ecb_ctz32 (x >> shift) + shift;
+ }
+
+ ecb_function_ int ecb_popcount32 (uint32_t x) ecb_const;
+ ecb_function_ int
+ ecb_popcount32 (uint32_t x)
+ {
+ x -= (x >> 1) & 0x55555555;
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ x = ((x >> 4) + x) & 0x0f0f0f0f;
+ x *= 0x01010101;
+
+ return x >> 24;
+ }
+
+ ecb_function_ int ecb_ld32 (uint32_t x) ecb_const;
+ ecb_function_ int ecb_ld32 (uint32_t x)
+ {
+ int r = 0;
+
+ if (x >> 16) { x >>= 16; r += 16; }
+ if (x >> 8) { x >>= 8; r += 8; }
+ if (x >> 4) { x >>= 4; r += 4; }
+ if (x >> 2) { x >>= 2; r += 2; }
+ if (x >> 1) { r += 1; }
+
+ return r;
+ }
+
+ ecb_function_ int ecb_ld64 (uint64_t x) ecb_const;
+ ecb_function_ int ecb_ld64 (uint64_t x)
+ {
+ int r = 0;
+
+ if (x >> 32) { x >>= 32; r += 32; }
+
+ return r + ecb_ld32 (x);
+ }
#endif
-#define expect_false(expr) expect ((expr) != 0, 0)
-#define expect_true(expr) expect ((expr) != 0, 1)
-#define inline_size static inline
+ecb_function_ uint8_t ecb_bitrev8 (uint8_t x) ecb_const;
+ecb_function_ uint8_t ecb_bitrev8 (uint8_t x)
+{
+ return ( (x * 0x0802U & 0x22110U)
+ | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16;
+}
+
+ecb_function_ uint16_t ecb_bitrev16 (uint16_t x) ecb_const;
+ecb_function_ uint16_t ecb_bitrev16 (uint16_t x)
+{
+ x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1);
+ x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2);
+ x = ((x >> 4) & 0x0f0f) | ((x & 0x0f0f) << 4);
+ x = ( x >> 8 ) | ( x << 8);
+
+ return x;
+}
+
+ecb_function_ uint32_t ecb_bitrev32 (uint32_t x) ecb_const;
+ecb_function_ uint32_t ecb_bitrev32 (uint32_t x)
+{
+ x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
+ x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
+ x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
+ x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
+ x = ( x >> 16 ) | ( x << 16);
+
+ return x;
+}
+
+/* popcount64 is only available on 64 bit cpus as gcc builtin */
+/* so for this version we are lazy */
+ecb_function_ int ecb_popcount64 (uint64_t x) ecb_const;
+ecb_function_ int
+ecb_popcount64 (uint64_t x)
+{
+ return ecb_popcount32 (x) + ecb_popcount32 (x >> 32);
+}
+
+ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) ecb_const;
+ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) ecb_const;
+ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) ecb_const;
+ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) ecb_const;
+ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) ecb_const;
+ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) ecb_const;
+ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) ecb_const;
+ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) ecb_const;
+
+ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); }
+ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); }
+ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); }
+ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); }
+ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); }
+ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); }
+ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); }
+ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); }
+
+#if ECB_GCC_VERSION(4,3)
+ #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16)
+ #define ecb_bswap32(x) __builtin_bswap32 (x)
+ #define ecb_bswap64(x) __builtin_bswap64 (x)
+#else
+ ecb_function_ uint16_t ecb_bswap16 (uint16_t x) ecb_const;
+ ecb_function_ uint16_t
+ ecb_bswap16 (uint16_t x)
+ {
+ return ecb_rotl16 (x, 8);
+ }
+
+ ecb_function_ uint32_t ecb_bswap32 (uint32_t x) ecb_const;
+ ecb_function_ uint32_t
+ ecb_bswap32 (uint32_t x)
+ {
+ return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16);
+ }
+
+ ecb_function_ uint64_t ecb_bswap64 (uint64_t x) ecb_const;
+ ecb_function_ uint64_t
+ ecb_bswap64 (uint64_t x)
+ {
+ return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32);
+ }
+#endif
+
+#if ECB_GCC_VERSION(4,5)
+ #define ecb_unreachable() __builtin_unreachable ()
+#else
+ /* this seems to work fine, but gcc always emits a warning for it :/ */
+ ecb_inline void ecb_unreachable (void) ecb_noreturn;
+ ecb_inline void ecb_unreachable (void) { }
+#endif
+
+/* try to tell the compiler that some condition is definitely true */
+#define ecb_assume(cond) do { if (!(cond)) ecb_unreachable (); } while (0)
+
+ecb_inline unsigned char ecb_byteorder_helper (void) ecb_const;
+ecb_inline unsigned char
+ecb_byteorder_helper (void)
+{
+ const uint32_t u = 0x11223344;
+ return *(unsigned char *)&u;
+}
+
+ecb_inline ecb_bool ecb_big_endian (void) ecb_const;
+ecb_inline ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11; }
+ecb_inline ecb_bool ecb_little_endian (void) ecb_const;
+ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44; }
+
+#if ECB_GCC_VERSION(3,0) || ECB_C99
+ #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0))
+#else
+ #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n)))
+#endif
+
+#if __cplusplus
+ template<typename T>
+ static inline T ecb_div_rd (T val, T div)
+ {
+ return val < 0 ? - ((-val + div - 1) / div) : (val ) / div;
+ }
+ template<typename T>
+ static inline T ecb_div_ru (T val, T div)
+ {
+ return val < 0 ? - ((-val ) / div) : (val + div - 1) / div;
+ }
+#else
+ #define ecb_div_rd(val,div) ((val) < 0 ? - ((-(val) + (div) - 1) / (div)) : ((val) ) / (div))
+ #define ecb_div_ru(val,div) ((val) < 0 ? - ((-(val) ) / (div)) : ((val) + (div) - 1) / (div))
+#endif
+
+#if ecb_cplusplus_does_not_suck
+ /* does not work for local types (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm) */
+ template<typename T, int N>
+ static inline int ecb_array_length (const T (&arr)[N])
+ {
+ return N;
+ }
+#else
+ #define ecb_array_length(name) (sizeof (name) / sizeof (name [0]))
+#endif
+
+#endif
+
+/* ECB.H END */
+
+#if ECB_MEMORY_FENCE_NEEDS_PTHREADS
+/* if your architecture doesn't need memory fences, e.g. because it is
+ * single-cpu/core, or if you use libev in a project that doesn't use libev
+ * from multiple threads, then you can define ECB_AVOID_PTHREADS when compiling
+ * libev, in which cases the memory fences become nops.
+ * alternatively, you can remove this #error and link against libpthread,
+ * which will then provide the memory fences.
+ */
+# error "memory fences not defined for your architecture, please report"
+#endif
+
+#ifndef ECB_MEMORY_FENCE
+# define ECB_MEMORY_FENCE do { } while (0)
+# define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
+# define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
+#endif
+
+#define expect_false(cond) ecb_expect_false (cond)
+#define expect_true(cond) ecb_expect_true (cond)
+#define noinline ecb_noinline
+
+#define inline_size ecb_inline
#if EV_FEATURE_CODE
-# define inline_speed static inline
+# define inline_speed ecb_inline
#else
# define inline_speed static noinline
#endif
@@ -524,11 +1003,59 @@ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work?
/*****************************************************************************/
+/* define a suitable floor function (only used by periodics atm) */
+
+#if EV_USE_FLOOR
+# include <math.h>
+# define ev_floor(v) floor (v)
+#else
+
+#include <float.h>
+
+/* a floor() replacement function, should be independent of ev_tstamp type */
+static ev_tstamp noinline
+ev_floor (ev_tstamp v)
+{
+ /* the choice of shift factor is not terribly important */
+#if FLT_RADIX != 2 /* assume FLT_RADIX == 10 */
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 10000000000000000000. : 1000000000.;
+#else
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 18446744073709551616. : 4294967296.;
+#endif
+
+ /* argument too large for an unsigned long? */
+ if (expect_false (v >= shift))
+ {
+ ev_tstamp f;
+
+ if (v == v - 1.)
+ return v; /* very large number */
+
+ f = shift * ev_floor (v * (1. / shift));
+ return f + ev_floor (v - f);
+ }
+
+ /* special treatment for negative args? */
+ if (expect_false (v < 0.))
+ {
+ ev_tstamp f = -ev_floor (-v);
+
+ return f - (f == v ? 0 : 1);
+ }
+
+ /* fits into an unsigned long */
+ return (unsigned long)v;
+}
+
+#endif
+
+/*****************************************************************************/
+
#ifdef __linux
# include <sys/utsname.h>
#endif
-static unsigned int noinline
+static unsigned int noinline ecb_cold
ev_linux_version (void)
{
#ifdef __linux
@@ -567,7 +1094,7 @@ ev_linux_version (void)
/*****************************************************************************/
#if EV_AVOID_STDIO
-static void noinline
+static void noinline ecb_cold
ev_printerr (const char *msg)
{
write (STDERR_FILENO, msg, strlen (msg));
@@ -576,13 +1103,13 @@ ev_printerr (const char *msg)
static void (*syserr_cb)(const char *msg);
-void
+void ecb_cold
ev_set_syserr_cb (void (*cb)(const char *msg))
{
syserr_cb = cb;
}
-static void noinline
+static void noinline ecb_cold
ev_syserr (const char *msg)
{
if (!msg)
@@ -625,7 +1152,7 @@ ev_realloc_emul (void *ptr, long size)
static void *(*alloc)(void *ptr, long size) = ev_realloc_emul;
-void
+void ecb_cold
ev_set_allocator (void *(*cb)(void *ptr, long size))
{
alloc = cb;
@@ -724,11 +1251,11 @@ typedef struct
#include "ev_wrap.h"
static struct ev_loop default_loop_struct;
- struct ev_loop *ev_default_loop_ptr;
+ EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */
#else
- ev_tstamp ev_rt_now;
+ EV_API_DECL ev_tstamp ev_rt_now = 0; /* needs to be initialised to make it a definition despite extern */
#define VAR(name,decl) static decl;
#include "ev_vars.h"
#undef VAR
@@ -832,7 +1359,7 @@ array_nextsize (int elem, int cur, int cnt)
ncur <<= 1;
while (cnt > ncur);
- /* if size is large, round to MALLOC_ROUND - 4 * longs to accomodate malloc overhead */
+ /* if size is large, round to MALLOC_ROUND - 4 * longs to accommodate malloc overhead */
if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4)
{
ncur *= elem;
@@ -844,7 +1371,7 @@ array_nextsize (int elem, int cur, int cnt)
return ncur;
}
-static noinline void *
+static void * noinline ecb_cold
array_realloc (int elem, void *base, int *cur, int cnt)
{
*cur = array_nextsize (elem, *cur, cnt);
@@ -857,7 +1384,7 @@ array_realloc (int elem, void *base, int *cur, int cnt)
#define array_needsize(type,base,cur,cnt,init) \
if (expect_false ((cnt) > (cur))) \
{ \
- int ocur_ = (cur); \
+ int ecb_unused ocur_ = (cur); \
(base) = (type *)array_realloc \
(sizeof (type), (base), &(cur), (cnt)); \
init ((base) + (ocur_), (cur) - ocur_); \
@@ -967,6 +1494,31 @@ 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 && anfd->head)
+ {
+ 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];
@@ -978,16 +1530,6 @@ fd_reify (EV_P)
anfd->reify = 0;
-#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP
- if (o_reify & EV__IOFDSET)
- {
- unsigned long arg;
- anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
- assert (("libev: only socket fds supported in this configuration", ioctlsocket (anfd->handle, FIONREAD, &arg) == 0));
- printf ("oi %d %x\n", fd, anfd->handle);//D
- }
-#endif
-
/*if (expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */
{
anfd->events = 0;
@@ -1022,7 +1564,7 @@ fd_change (EV_P_ int fd, int flags)
}
/* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */
-inline_speed void
+inline_speed void ecb_cold
fd_kill (EV_P_ int fd)
{
ev_io *w;
@@ -1035,7 +1577,7 @@ fd_kill (EV_P_ int fd)
}
/* check whether the given fd is actually valid, for error recovery */
-inline_size int
+inline_size int ecb_cold
fd_valid (int fd)
{
#ifdef _WIN32
@@ -1046,7 +1588,7 @@ fd_valid (int fd)
}
/* called on EBADF to verify fds */
-static void noinline
+static void noinline ecb_cold
fd_ebadf (EV_P)
{
int fd;
@@ -1058,7 +1600,7 @@ fd_ebadf (EV_P)
}
/* called on ENOMEM in select/poll to kill some fds and retry */
-static void noinline
+static void noinline ecb_cold
fd_enomem (EV_P)
{
int fd;
@@ -1263,7 +1805,7 @@ static ANSIG signals [EV_NSIG - 1];
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
-static void noinline
+static void noinline ecb_cold
evpipe_init (EV_P)
{
if (!ev_is_active (&pipe_w))
@@ -1295,15 +1837,27 @@ evpipe_init (EV_P)
}
}
-inline_size void
+inline_speed void
evpipe_write (EV_P_ EV_ATOMIC_T *flag)
{
- if (!*flag)
+ if (expect_true (*flag))
+ return;
+
+ *flag = 1;
+
+ ECB_MEMORY_FENCE_RELEASE; /* make sure flag is visible before the wakeup */
+
+ pipe_write_skipped = 1;
+
+ ECB_MEMORY_FENCE; /* make sure pipe_write_skipped is visible before we check pipe_write_wanted */
+
+ if (pipe_write_wanted)
{
- int old_errno = errno; /* save errno because write might clobber it */
- char dummy;
+ int old_errno;
- *flag = 1;
+ pipe_write_skipped = 0; /* just an optimisation, no fence needed */
+
+ old_errno = errno; /* save errno because write will clobber it */
#if EV_USE_EVENTFD
if (evfd >= 0)
@@ -1313,12 +1867,14 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
}
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);
+ {
+ /* 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], &(evpipe [1]), 1);
+ }
errno = old_errno;
}
@@ -1331,28 +1887,35 @@ pipecb (EV_P_ ev_io *iow, int revents)
{
int i;
-#if EV_USE_EVENTFD
- if (evfd >= 0)
+ if (revents & EV_READ)
{
- uint64_t counter;
- read (evfd, &counter, sizeof (uint64_t));
- }
- else
+#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);
+ {
+ char dummy;
+ /* see discussion in evpipe_write when you think this read should be recv in win32 */
+ read (evpipe [0], &dummy, 1);
+ }
}
+ pipe_write_skipped = 0;
+
+#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)
@@ -1381,6 +1944,9 @@ ev_feed_signal (int signum)
return;
#endif
+ if (!ev_active (&pipe_w))
+ return;
+
signals [signum - 1].pending = 1;
evpipe_write (EV_A_ &sig_pending);
}
@@ -1521,20 +2087,20 @@ childcb (EV_P_ ev_signal *sw, int revents)
# include "ev_select.c"
#endif
-int
+int ecb_cold
ev_version_major (void)
{
return EV_VERSION_MAJOR;
}
-int
+int ecb_cold
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
+int inline_size ecb_cold
enable_secure (void)
{
#ifdef _WIN32
@@ -1545,7 +2111,7 @@ enable_secure (void)
#endif
}
-unsigned int
+unsigned int ecb_cold
ev_supported_backends (void)
{
unsigned int flags = 0;
@@ -1559,7 +2125,7 @@ ev_supported_backends (void)
return flags;
}
-unsigned int
+unsigned int ecb_cold
ev_recommended_backends (void)
{
unsigned int flags = ev_supported_backends ();
@@ -1581,7 +2147,7 @@ ev_recommended_backends (void)
return flags;
}
-unsigned int
+unsigned int ecb_cold
ev_embeddable_backends (void)
{
int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT;
@@ -1636,12 +2202,14 @@ ev_userdata (EV_P)
return userdata;
}
-void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P))
+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))
+void
+ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
{
release_cb = release;
acquire_cb = acquire;
@@ -1649,7 +2217,7 @@ void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
#endif
/* initialise a loop structure, must be zero-initialised */
-static void noinline
+static void noinline ecb_cold
loop_init (EV_P_ unsigned int flags)
{
if (!backend)
@@ -1687,27 +2255,29 @@ loop_init (EV_P_ unsigned int flags)
&& 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;
+ 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;
+ invoke_cb = ev_invoke_pending;
#endif
- io_blocktime = 0.;
- timeout_blocktime = 0.;
- backend = 0;
- backend_fd = -1;
- sig_pending = 0;
+ io_blocktime = 0.;
+ timeout_blocktime = 0.;
+ backend = 0;
+ backend_fd = -1;
+ sig_pending = 0;
#if EV_ASYNC_ENABLE
- async_pending = 0;
+ async_pending = 0;
#endif
+ pipe_write_skipped = 0;
+ pipe_write_wanted = 0;
#if EV_USE_INOTIFY
- fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
+ fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
#endif
#if EV_USE_SIGNALFD
- sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
+ sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
#endif
if (!(flags & EVBACKEND_MASK))
@@ -1742,7 +2312,7 @@ loop_init (EV_P_ unsigned int flags)
}
/* free up a loop structure */
-void
+void ecb_cold
ev_loop_destroy (EV_P)
{
int i;
@@ -1882,12 +2452,7 @@ loop_fork (EV_P)
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
+ /* pipe_write_wanted must be false now, so modifying fd vars should be safe */
ev_ref (EV_A);
ev_io_stop (EV_A_ &pipe_w);
@@ -1915,7 +2480,7 @@ loop_fork (EV_P)
#if EV_MULTIPLICITY
-struct ev_loop *
+struct ev_loop * ecb_cold
ev_loop_new (unsigned int flags)
{
EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
@@ -1933,7 +2498,7 @@ ev_loop_new (unsigned int flags)
#endif /* multiplicity */
#if EV_VERIFY
-static void noinline
+static void noinline ecb_cold
verify_watcher (EV_P_ W w)
{
assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI));
@@ -1942,7 +2507,7 @@ verify_watcher (EV_P_ W w)
assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w));
}
-static void noinline
+static void noinline ecb_cold
verify_heap (EV_P_ ANHE *heap, int N)
{
int i;
@@ -1957,7 +2522,7 @@ verify_heap (EV_P_ ANHE *heap, int N)
}
}
-static void noinline
+static void noinline ecb_cold
array_verify (EV_P_ W *ws, int cnt)
{
while (cnt--)
@@ -1969,7 +2534,7 @@ array_verify (EV_P_ W *ws, int cnt)
#endif
#if EV_FEATURE_API
-void
+void ecb_cold
ev_verify (EV_P)
{
#if EV_VERIFY
@@ -2045,7 +2610,7 @@ ev_verify (EV_P)
#endif
#if EV_MULTIPLICITY
-struct ev_loop *
+struct ev_loop * ecb_cold
#else
int
#endif
@@ -2183,6 +2748,31 @@ timers_reify (EV_P)
}
#if EV_PERIODIC_ENABLE
+
+static void noinline
+periodic_recalc (EV_P_ ev_periodic *w)
+{
+ ev_tstamp interval = w->interval > MIN_INTERVAL ? w->interval : MIN_INTERVAL;
+ ev_tstamp at = w->offset + interval * ev_floor ((ev_rt_now - w->offset) / interval);
+
+ /* the above almost always errs on the low side */
+ while (at <= ev_rt_now)
+ {
+ ev_tstamp nat = at + w->interval;
+
+ /* when resolution fails us, we use ev_rt_now */
+ if (expect_false (nat == at))
+ {
+ at = ev_rt_now;
+ break;
+ }
+
+ at = nat;
+ }
+
+ ev_at (w) = at;
+}
+
/* make periodics pending */
inline_size void
periodics_reify (EV_P)
@@ -2211,20 +2801,7 @@ periodics_reify (EV_P)
}
else if (w->interval)
{
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
- /* 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;
- }
-
+ periodic_recalc (EV_A_ w);
ANHE_at_cache (periodics [HEAP0]);
downheap (periodics, periodiccnt, HEAP0);
}
@@ -2242,7 +2819,7 @@ periodics_reify (EV_P)
/* simply recalculate all periodics */
/* TODO: maybe ensure that at least one event happens when jumping forward? */
-static void noinline
+static void noinline ecb_cold
periodics_reschedule (EV_P)
{
int i;
@@ -2255,7 +2832,7 @@ periodics_reschedule (EV_P)
if (w->reschedule_cb)
ev_at (w) = w->reschedule_cb (w, ev_rt_now);
else if (w->interval)
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
+ periodic_recalc (EV_A_ w);
ANHE_at_cache (periodics [i]);
}
@@ -2265,7 +2842,7 @@ periodics_reschedule (EV_P)
#endif
/* adjust all timers by a given offset */
-static void noinline
+static void noinline ecb_cold
timers_reschedule (EV_P_ ev_tstamp adjust)
{
int i;
@@ -2312,9 +2889,12 @@ time_update (EV_P_ ev_tstamp max_block)
*/
for (i = 4; --i; )
{
+ ev_tstamp diff;
rtmn_diff = ev_rt_now - mn_now;
- if (expect_true (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP))
+ diff = odiff - rtmn_diff;
+
+ if (expect_true ((diff < 0. ? -diff : diff) < MIN_TIMEJUMP))
return; /* all is well */
ev_rt_now = ev_time ();
@@ -2414,20 +2994,25 @@ ev_run (EV_P_ int flags)
/* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100);
- if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
+ /* from now on, we want a pipe-wake-up */
+ pipe_write_wanted = 1;
+
+ ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */
+
+ if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
{
waittime = MAX_BLOCKTIME;
if (timercnt)
{
- ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge;
+ ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
if (waittime > to) waittime = to;
}
#if EV_PERIODIC_ENABLE
if (periodiccnt)
{
- ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge;
+ ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
if (waittime > to) waittime = to;
}
#endif
@@ -2436,13 +3021,18 @@ ev_run (EV_P_ int flags)
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime;
+ /* at this point, we NEED to wait, so we have to ensure */
+ /* to pass a minimum nonzero value to the backend */
+ if (expect_false (waittime < backend_mintime))
+ waittime = backend_mintime;
+
/* 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 (sleeptime > waittime - backend_mintime)
+ sleeptime = waittime - backend_mintime;
if (expect_true (sleeptime > 0.))
{
@@ -2459,6 +3049,15 @@ ev_run (EV_P_ int flags)
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
+ pipe_write_wanted = 0; /* just an optimisation, no fence needed */
+
+ if (pipe_write_skipped)
+ {
+ assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
+ ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
+ }
+
+
/* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
}
@@ -2719,6 +3318,8 @@ ev_timer_again (EV_P_ ev_timer *w)
{
EV_FREQUENT_CHECK;
+ clear_pending (EV_A_ (W)w);
+
if (ev_is_active (w))
{
if (w->repeat)
@@ -2757,8 +3358,7 @@ ev_periodic_start (EV_P_ ev_periodic *w)
else if (w->interval)
{
assert (("libev: ev_periodic_start called with negative interval value", w->interval >= 0.));
- /* this formula differs from the one in periodic_reify because we do not always round up */
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
+ periodic_recalc (EV_A_ w);
}
else
ev_at (w) = w->offset;
@@ -3045,7 +3645,7 @@ infy_add (EV_P_ ev_stat *w)
*pend = 0;
w->wd = inotify_add_watch (fs_fd, path, mask);
- }
+ }
while (w->wd < 0 && (errno == ENOENT || errno == EACCES));
}
}
@@ -3122,7 +3722,7 @@ infy_cb (EV_P_ ev_io *w, int revents)
}
}
-inline_size void
+inline_size void ecb_cold
ev_check_2625 (EV_P)
{
/* kernels < 2.6.25 are borked
@@ -3757,7 +4357,7 @@ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, vo
/*****************************************************************************/
#if EV_WALK_ENABLE
-void
+void ecb_cold
ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
{
int i, j;
@@ -3811,7 +4411,7 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
#if EV_IDLE_ENABLE
if (types & EV_IDLE)
- for (j = NUMPRI; i--; )
+ for (j = NUMPRI; j--; )
for (i = idlecnt [j]; i--; )
cb (EV_A_ EV_IDLE, idles [j][i]);
#endif
@@ -3874,5 +4474,3 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
#include "ev_wrap.h"
#endif
-EV_CPP(})
-
diff --git a/libev/ev.h b/libev/ev.h
index 9edf656..54b4f00 100644
--- a/libev/ev.h
+++ b/libev/ev.h
@@ -1,19 +1,19 @@
/*
* libev native API header
*
- * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libev@schmorp.de>
* 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
@@ -185,7 +185,13 @@ struct ev_loop;
# define EV_INLINE static
#endif
-/* EV_PROTOTYPES can be sued to switch of prototype declarations */
+#ifdef EV_API_STATIC
+# define EV_API_DECL static
+#else
+# define EV_API_DECL extern
+#endif
+
+/* EV_PROTOTYPES can be used to switch of prototype declarations */
#ifndef EV_PROTOTYPES
# define EV_PROTOTYPES 1
#endif
@@ -193,7 +199,7 @@ struct ev_loop;
/*****************************************************************************/
#define EV_VERSION_MAJOR 4
-#define EV_VERSION_MINOR 3
+#define EV_VERSION_MINOR 11
/* eventmask, revents, events... */
enum {
@@ -508,15 +514,15 @@ enum {
};
#if EV_PROTOTYPES
-int ev_version_major (void);
-int ev_version_minor (void);
+EV_API_DECL int ev_version_major (void);
+EV_API_DECL int ev_version_minor (void);
-unsigned int ev_supported_backends (void);
-unsigned int ev_recommended_backends (void);
-unsigned int ev_embeddable_backends (void);
+EV_API_DECL unsigned int ev_supported_backends (void);
+EV_API_DECL unsigned int ev_recommended_backends (void);
+EV_API_DECL unsigned int ev_embeddable_backends (void);
-ev_tstamp ev_time (void);
-void ev_sleep (ev_tstamp delay); /* sleep for a while */
+EV_API_DECL ev_tstamp ev_time (void);
+EV_API_DECL 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.
@@ -524,19 +530,23 @@ void ev_sleep (ev_tstamp delay); /* sleep for a while */
* or take some potentially destructive action.
* The default is your system realloc function.
*/
-void ev_set_allocator (void *(*cb)(void *ptr, long size));
+EV_API_DECL 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));
+EV_API_DECL 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_API_DECL struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0));
+
+#ifdef EV_API_STATIC
+EV_API_DECL struct ev_loop *ev_default_loop_ptr;
+#endif
EV_INLINE struct ev_loop *
ev_default_loop_uc_ (void)
@@ -553,19 +563,19 @@ ev_is_default_loop (EV_P)
}
/* create and destroy alternative loops that don't handle signals */
-struct ev_loop *ev_loop_new (unsigned int flags EV_CPP (= 0));
+EV_API_DECL 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 */
+EV_API_DECL 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_API_DECL int ev_default_loop (unsigned int flags EV_CPP (= 0)); /* returns true when successful */
+
+EV_API_DECL ev_tstamp ev_rt_now;
EV_INLINE ev_tstamp
ev_now (void)
{
- extern ev_tstamp ev_rt_now;
-
return ev_rt_now;
}
@@ -579,23 +589,23 @@ ev_is_default_loop (void)
#endif /* multiplicity */
/* destroy event loops, also works for the default loop */
-void ev_loop_destroy (EV_P);
+EV_API_DECL 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);
+EV_API_DECL void ev_loop_fork (EV_P);
-unsigned int ev_backend (EV_P); /* backend in use by loop */
+EV_API_DECL unsigned int ev_backend (EV_P); /* backend in use by loop */
-void ev_now_update (EV_P); /* update event loop time */
+EV_API_DECL 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));
+EV_API_DECL void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w));
#endif
#endif /* prototypes */
@@ -614,45 +624,45 @@ enum {
};
#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 */
+EV_API_DECL void ev_run (EV_P_ int flags EV_CPP (= 0));
+EV_API_DECL 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);
+EV_API_DECL void ev_ref (EV_P);
+EV_API_DECL 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);
+EV_API_DECL 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 */
+EV_API_DECL unsigned int ev_iteration (EV_P); /* number of loop iterations */
+EV_API_DECL unsigned int ev_depth (EV_P); /* #ev_loop enters - #ev_loop leaves */
+EV_API_DECL 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 */
+EV_API_DECL void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */
+EV_API_DECL 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));
+EV_API_DECL void ev_set_userdata (EV_P_ void *data);
+EV_API_DECL void *ev_userdata (EV_P);
+EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P));
+EV_API_DECL 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 */
+EV_API_DECL unsigned int ev_pending_count (EV_P); /* number of pending events, if any */
+EV_API_DECL 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);
+EV_API_DECL void ev_suspend (EV_P);
+EV_API_DECL void ev_resume (EV_P);
#endif
#endif
@@ -717,87 +727,87 @@ void ev_resume (EV_P);
/* 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 */
+/* feeds an event into a watcher as if the event actually occurred */
/* 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);
+EV_API_DECL void ev_feed_event (EV_P_ void *w, int revents);
+EV_API_DECL 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);
+EV_API_DECL void ev_feed_signal (int signum);
+EV_API_DECL 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);
+EV_API_DECL void ev_invoke (EV_P_ void *w, int revents);
+EV_API_DECL 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);
+EV_API_DECL void ev_io_start (EV_P_ ev_io *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_timer_start (EV_P_ ev_timer *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_timer_again (EV_P_ ev_timer *w);
/* return remaining time */
-ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_periodic_start (EV_P_ ev_periodic *w);
+EV_API_DECL void ev_periodic_stop (EV_P_ ev_periodic *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_signal_start (EV_P_ ev_signal *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_child_start (EV_P_ ev_child *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_stat_start (EV_P_ ev_stat *w);
+EV_API_DECL void ev_stat_stop (EV_P_ ev_stat *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_idle_start (EV_P_ ev_idle *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_prepare_start (EV_P_ ev_prepare *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_check_start (EV_P_ ev_check *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_fork_start (EV_P_ ev_fork *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_cleanup_start (EV_P_ ev_cleanup *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_embed_start (EV_P_ ev_embed *w);
+EV_API_DECL void ev_embed_stop (EV_P_ ev_embed *w);
+EV_API_DECL 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);
+EV_API_DECL void ev_async_start (EV_P_ ev_async *w);
+EV_API_DECL void ev_async_stop (EV_P_ ev_async *w);
+EV_API_DECL void ev_async_send (EV_P_ ev_async *w);
# endif
#if EV_COMPAT3
diff --git a/libev/ev.pod b/libev/ev.pod
index 6cd777e..2de0277 100644
--- a/libev/ev.pod
+++ b/libev/ev.pod
@@ -60,7 +60,7 @@ libev - a high performance full-featured event loop written in C
// now wait for events to arrive
ev_run (loop, 0);
- // unloop was called, so exit
+ // break was called, so exit
return 0;
}
@@ -176,13 +176,19 @@ library in any way.
Returns the current time as libev would use it. Please note that the
C<ev_now> function is usually faster and also often returns the timestamp
you actually want to know. Also interesting is the combination of
-C<ev_update_now> and C<ev_now>.
+C<ev_now_update> and C<ev_now>.
=item ev_sleep (ev_tstamp interval)
-Sleep for the given interval: The current thread will be blocked until
-either it is interrupted or the given time interval has passed. Basically
-this is a sub-second-resolution C<sleep ()>.
+Sleep for the given interval: The current thread will be blocked
+until either it is interrupted or the given time interval has
+passed (approximately - it might return a bit earlier even if not
+interrupted). Returns immediately if C<< interval <= 0 >>.
+
+Basically this is a sub-second-resolution C<sleep ()>.
+
+The range of the C<interval> is limited - libev only guarantees to work
+with sleep times of up to one day (C<< interval <= 86400 >>).
=item int ev_version_major ()
@@ -437,13 +443,16 @@ example) that can't properly initialise their signal masks.
=item C<EVFLAG_NOSIGMASK>
When this flag is specified, then libev will avoid to modify the signal
-mask. Specifically, this means you ahve to make sure signals are unblocked
+mask. Specifically, this means you have to make sure signals are unblocked
when you want to receive them.
This behaviour is useful when you want to do your own signal handling, or
want to handle signals only in specific threads and want to avoid libev
unblocking the signals.
+It's also required by POSIX in a threaded program, as libev calls
+C<sigprocmask>, whose behaviour is officially unspecified.
+
This flag's behaviour will become the default in future versions of libev.
=item C<EVBACKEND_SELECT> (value 1, portable select backend)
@@ -482,10 +491,10 @@ C<EV_WRITE> to C<POLLOUT | POLLERR | POLLHUP>.
Use the linux-specific epoll(7) interface (for both pre- and post-2.6.9
kernels).
-For few fds, this backend is a bit little slower than poll and select,
-but it scales phenomenally better. While poll and select usually scale
-like O(total_fds) where n is the total number of fds (or the highest fd),
-epoll scales either O(1) or O(active_fds).
+For few fds, this backend is a bit little slower than poll and select, but
+it scales phenomenally better. While poll and select usually scale like
+O(total_fds) where total_fds is the total number of fds (or the highest
+fd), epoll scales either O(1) or O(active_fds).
The epoll mechanism deserves honorable mention as the most misdesigned
of the more advanced event mechanisms: mere annoyances include silently
@@ -498,19 +507,22 @@ forks then I<both> parent and child process have to recreate the epoll
set, which can take considerable time (one syscall per file descriptor)
and is of course hard to detect.
-Epoll is also notoriously buggy - embedding epoll fds I<should> work, but
-of course I<doesn't>, and epoll just loves to report events for totally
-I<different> file descriptors (even already closed ones, so one cannot
-even remove them from the set) than registered in the set (especially
-on SMP systems). Libev tries to counter these spurious notifications by
-employing an additional generation counter and comparing that against the
-events to filter out spurious ones, recreating the set when required. Last
+Epoll is also notoriously buggy - embedding epoll fds I<should> work,
+but of course I<doesn't>, and epoll just loves to report events for
+totally I<different> file descriptors (even already closed ones, so
+one cannot even remove them from the set) than registered in the set
+(especially on SMP systems). Libev tries to counter these spurious
+notifications by employing an additional generation counter and comparing
+that against the events to filter out spurious ones, recreating the set
+when required. Epoll also erroneously rounds down timeouts, but gives you
+no way to know when and by how much, so sometimes you have to busy-wait
+because epoll returns immediately despite a nonzero timeout. And last
not least, it also refuses to work with some file descriptors which work
perfectly fine with C<select> (files, many character devices...).
-Epoll is truly the train wreck analog among event poll mechanisms,
-a frankenpoll, cobbled together in a hurry, no thought to design or
-interaction with others.
+Epoll is truly the train wreck among event poll mechanisms, a frankenpoll,
+cobbled together in a hurry, no thought to design or interaction with
+others. Oh, the pain, will it ever stop...
While stopping, setting and starting an I/O watcher in the same iteration
will result in some caching, there is still a system call per such
@@ -598,11 +610,11 @@ hacks).
On the negative side, the interface is I<bizarre> - so bizarre that
even sun itself gets it wrong in their code examples: The event polling
-function sometimes returning events to the caller even though an error
+function sometimes returns events to the caller even though an error
occurred, but with no indication whether it has done so or not (yes, it's
-even documented that way) - deadly for edge-triggered interfaces where
-you absolutely have to know whether an event occurred or not because you
-have to re-arm the watcher.
+even documented that way) - deadly for edge-triggered interfaces where you
+absolutely have to know whether an event occurred or not because you have
+to re-arm the watcher.
Fortunately libev seems to be able to work around these idiocies.
@@ -824,7 +836,9 @@ with something not expressible using other libev watchers (i.e. "roll your
own C<ev_run>"). However, a pair of C<ev_prepare>/C<ev_check> watchers is
usually a better approach for this kind of thing.
-Here are the gory details of what C<ev_run> does:
+Here are the gory details of what C<ev_run> does (this is for your
+understanding, not a guarantee that things will work exactly like this in
+future versions):
- Increment loop depth.
- Reset the ev_break status.
@@ -867,7 +881,7 @@ anymore.
... queue jobs here, make sure they register event watchers as long
... as they still have work to do (even an idle watcher will do..)
ev_run (my_loop, 0);
- ... jobs done or somebody called unloop. yeah!
+ ... jobs done or somebody called break. yeah!
=item ev_break (loop, how)
@@ -940,10 +954,11 @@ overhead for the actual polling but can deliver many events at once.
By setting a higher I<io collect interval> you allow libev to spend more
time collecting I/O events, so you can handle more events per iteration,
at the cost of increasing latency. Timeouts (both C<ev_periodic> and
-C<ev_timer>) will be not affected. Setting this to a non-null value will
+C<ev_timer>) will not be affected. Setting this to a non-null value will
introduce an additional C<ev_sleep ()> call into most loop iterations. The
sleep time ensures that libev will not poll for I/O events more often then
-once per this interval, on average.
+once per this interval, on average (as long as the host time resolution is
+good enough).
Likewise, by setting a higher I<timeout collect interval> you allow libev
to spend more time collecting timeouts, at the expense of increased
@@ -1007,7 +1022,7 @@ each call to a libev function.
However, C<ev_run> can run an indefinite time, so it is not feasible
to wait for it to return. One way around this is to wake up the event
-loop via C<ev_break> and C<av_async_send>, another way is to set these
+loop via C<ev_break> and C<ev_async_send>, another way is to set these
I<release> and I<acquire> callbacks on the loop.
When set, then C<release> will be called just before the thread is
@@ -1373,12 +1388,14 @@ rules might look complicated, they usually do "the right thing".
=item initialiased
-Before a watcher can be registered with the event looop it has to be
+Before a watcher can be registered with the event loop it has to be
initialised. This can be done with a call to C<ev_TYPE_init>, or calls to
C<ev_init> followed by the watcher-specific C<ev_TYPE_set> function.
-In this state it is simply some block of memory that is suitable for use
-in an event loop. It can be moved around, freed, reused etc. at will.
+In this state it is simply some block of memory that is suitable for
+use in an event loop. It can be moved around, freed, reused etc. at
+will - as long as you either keep the memory contents intact, or call
+C<ev_TYPE_init> again.
=item started/running/active
@@ -1416,8 +1433,9 @@ of whether it was active or not, so stopping a watcher explicitly before
freeing it is often a good idea.
While stopped (and not pending) the watcher is essentially in the
-initialised state, that is it can be reused, moved, modified in any way
-you wish.
+initialised state, that is, it can be reused, moved, modified in any way
+you wish (but when you trash the memory block, you need to C<ev_TYPE_init>
+it again).
=back
@@ -1755,10 +1773,11 @@ monotonic clock option helps a lot here).
The callback is guaranteed to be invoked only I<after> its timeout has
passed (not I<at>, so on systems with very low-resolution clocks this
-might introduce a small delay). If multiple timers become ready during the
-same loop iteration then the ones with earlier time-out values are invoked
-before ones of the same priority with later time-out values (but this is
-no longer true when a callback calls C<ev_run> recursively).
+might introduce a small delay, see "the special problem of being too
+early", below). If multiple timers become ready during the same loop
+iteration then the ones with earlier time-out values are invoked before
+ones of the same priority with later time-out values (but this is no
+longer true when a callback calls C<ev_run> recursively).
=head3 Be smart about timeouts
@@ -1843,63 +1862,77 @@ In this case, it would be more efficient to leave the C<ev_timer> alone,
but remember the time of last activity, and check for a real timeout only
within the callback:
+ ev_tstamp timeout = 60.;
ev_tstamp last_activity; // time of last activity
+ ev_timer timer;
static void
callback (EV_P_ ev_timer *w, int revents)
{
- ev_tstamp now = ev_now (EV_A);
- ev_tstamp timeout = last_activity + 60.;
+ // calculate when the timeout would happen
+ ev_tstamp after = last_activity - ev_now (EV_A) + timeout;
- // if last_activity + 60. is older than now, we did time out
- if (timeout < now)
+ // if negative, it means we the timeout already occured
+ if (after < 0.)
{
// timeout occurred, take action
}
else
{
- // callback was invoked, but there was some activity, re-arm
- // the watcher to fire in last_activity + 60, which is
- // guaranteed to be in the future, so "again" is positive:
- w->repeat = timeout - now;
- ev_timer_again (EV_A_ w);
+ // callback was invoked, but there was some recent
+ // activity. simply restart the timer to time out
+ // after "after" seconds, which is the earliest time
+ // the timeout can occur.
+ ev_timer_set (w, after, 0.);
+ ev_timer_start (EV_A_ w);
}
}
-To summarise the callback: first calculate the real timeout (defined
-as "60 seconds after the last activity"), then check if that time has
-been reached, which means something I<did>, in fact, time out. Otherwise
-the callback was invoked too early (C<timeout> is in the future), so
-re-schedule the timer to fire at that future time, to see if maybe we have
-a timeout then.
+To summarise the callback: first calculate in how many seconds the
+timeout will occur (by calculating the absolute time when it would occur,
+C<last_activity + timeout>, and subtracting the current time, C<ev_now
+(EV_A)> from that).
+
+If this value is negative, then we are already past the timeout, i.e. we
+timed out, and need to do whatever is needed in this case.
-Note how C<ev_timer_again> is used, taking advantage of the
-C<ev_timer_again> optimisation when the timer is already running.
+Otherwise, we now the earliest time at which the timeout would trigger,
+and simply start the timer with this timeout value.
+
+In other words, each time the callback is invoked it will check whether
+the timeout cocured. If not, it will simply reschedule itself to check
+again at the earliest time it could time out. Rinse. Repeat.
This scheme causes more callback invocations (about one every 60 seconds
minus half the average time between activity), but virtually no calls to
libev to change the timeout.
-To start the timer, simply initialise the watcher and set C<last_activity>
-to the current time (meaning we just have some activity :), then call the
-callback, which will "do the right thing" and start the timer:
+To start the machinery, simply initialise the watcher and set
+C<last_activity> to the current time (meaning there was some activity just
+now), then call the callback, which will "do the right thing" and start
+the timer:
- ev_init (timer, callback);
- last_activity = ev_now (loop);
- callback (loop, timer, EV_TIMER);
+ last_activity = ev_now (EV_A);
+ ev_init (&timer, callback);
+ callback (EV_A_ &timer, 0);
-And when there is some activity, simply store the current time in
+When there is some activity, simply store the current time in
C<last_activity>, no libev calls at all:
- last_activity = ev_now (loop);
+ if (activity detected)
+ last_activity = ev_now (EV_A);
+
+When your timeout value changes, then the timeout can be changed by simply
+providing a new value, stopping the timer and calling the callback, which
+will agaion do the right thing (for example, time out immediately :).
+
+ timeout = new_value;
+ ev_timer_stop (EV_A_ &timer);
+ callback (EV_A_ &timer, 0);
This technique is slightly more complex, but in most cases where the
time-out is unlikely to be triggered, much more efficient.
-Changing the timeout is trivial as well (if it isn't hard-coded in the
-callback :) - just change the timeout and invoke the callback, which will
-fix things for you.
-
=item 4. Wee, just use a double-linked list for your timeouts.
If there is not one request, but many thousands (millions...), all
@@ -1935,10 +1968,47 @@ rather complicated, but extremely efficient, something that really pays
off after the first million or so of active timers, i.e. it's usually
overkill :)
+=head3 The special problem of being too early
+
+If you ask a timer to call your callback after three seconds, then
+you expect it to be invoked after three seconds - but of course, this
+cannot be guaranteed to infinite precision. Less obviously, it cannot be
+guaranteed to any precision by libev - imagine somebody suspending the
+process with a STOP signal for a few hours for example.
+
+So, libev tries to invoke your callback as soon as possible I<after> the
+delay has occurred, but cannot guarantee this.
+
+A less obvious failure mode is calling your callback too early: many event
+loops compare timestamps with a "elapsed delay >= requested delay", but
+this can cause your callback to be invoked much earlier than you would
+expect.
+
+To see why, imagine a system with a clock that only offers full second
+resolution (think windows if you can't come up with a broken enough OS
+yourself). If you schedule a one-second timer at the time 500.9, then the
+event loop will schedule your timeout to elapse at a system time of 500
+(500.9 truncated to the resolution) + 1, or 501.
+
+If an event library looks at the timeout 0.1s later, it will see "501 >=
+501" and invoke the callback 0.1s after it was started, even though a
+one-second delay was requested - this is being "too early", despite best
+intentions.
+
+This is the reason why libev will never invoke the callback if the elapsed
+delay equals the requested delay, but only when the elapsed delay is
+larger than the requested delay. In the example above, libev would only invoke
+the callback at system time 502, or 1.1s after the timer was started.
+
+So, while libev cannot guarantee that your callback will be invoked
+exactly when requested, it I<can> and I<does> guarantee that the requested
+delay has actually elapsed, or in other words, it always errs on the "too
+late" side of things.
+
=head3 The special problem of time updates
-Establishing the current time is a costly operation (it usually takes at
-least two system calls): EV therefore updates its idea of the current
+Establishing the current time is a costly operation (it usually takes
+at least one system call): EV therefore updates its idea of the current
time only before and after C<ev_run> collects new events, which causes a
growing difference between C<ev_now ()> and C<ev_time ()> when handling
lots of events in one iteration.
@@ -1955,6 +2025,39 @@ If the event loop is suspended for a long time, you can also force an
update of the time returned by C<ev_now ()> by calling C<ev_now_update
()>.
+=head3 The special problem of unsynchronised clocks
+
+Modern systems have a variety of clocks - libev itself uses the normal
+"wall clock" clock and, if available, the monotonic clock (to avoid time
+jumps).
+
+Neither of these clocks is synchronised with each other or any other clock
+on the system, so C<ev_time ()> might return a considerably different time
+than C<gettimeofday ()> or C<time ()>. On a GNU/Linux system, for example,
+a call to C<gettimeofday> might return a second count that is one higher
+than a directly following call to C<time>.
+
+The moral of this is to only compare libev-related timestamps with
+C<ev_time ()> and C<ev_now ()>, at least if you want better precision than
+a second or so.
+
+One more problem arises due to this lack of synchronisation: if libev uses
+the system monotonic clock and you compare timestamps from C<ev_time>
+or C<ev_now> from when you started your timer and when your callback is
+invoked, you will find that sometimes the callback is a bit "early".
+
+This is because C<ev_timer>s work in real time, not wall clock time, so
+libev makes sure your callback is not invoked before the delay happened,
+I<measured according to the real time>, not the system clock.
+
+If your timeouts are based on a physical timescale (e.g. "time out this
+connection after 100 seconds") then this shouldn't bother you as it is
+exactly the right behaviour.
+
+If you want to compare wall clock/system timestamps to your timers, then
+you need to use C<ev_periodic>s, as these are based on the wall clock
+time, where your comparisons will always generate correct results.
+
=head3 The special problems of suspended animation
When you leave the server world it is quite customary to hit machines that
@@ -2007,15 +2110,24 @@ do stuff) the timer will not fire more than once per event loop iteration.
=item ev_timer_again (loop, ev_timer *)
-This will act as if the timer timed out and restart it again if it is
-repeating. The exact semantics are:
+This will act as if the timer timed out, and restarts it again if it is
+repeating. It basically works like calling C<ev_timer_stop>, updating the
+timeout to the C<repeat> value and calling C<ev_timer_start>.
+
+The exact semantics are as in the following rules, all of which will be
+applied to the watcher:
+
+=over 4
+
+=item If the timer is pending, the pending status is always cleared.
-If the timer is pending, its pending status is cleared.
+=item If the timer is started but non-repeating, stop it (as if it timed
+out, without invoking it).
-If the timer is started but non-repeating, stop it (as if it timed out).
+=item If the timer is repeating, make the C<repeat> value the new timeout
+and start the timer, if necessary.
-If the timer is repeating, either start it if necessary (with the
-C<repeat> value), or reset the running timer to the C<repeat> value.
+=back
This sounds a bit complicated, see L<Be smart about timeouts>, above, for a
usage example.
@@ -2147,9 +2259,12 @@ Another way to think about it (for the mathematically inclined) is that
C<ev_periodic> will try to run the callback in this mode at the next possible
time where C<time = offset (mod interval)>, regardless of any time jumps.
-For numerical stability it is preferable that the C<offset> value is near
-C<ev_now ()> (the current time), but there is no range requirement for
-this value, and in fact is often specified as zero.
+The C<interval> I<MUST> be positive, and for numerical stability, the
+interval value should be higher than C<1/8192> (which is around 100
+microseconds) and C<offset> should be higher than C<0> and should have
+at most a similar magnitude as the current time (say, within a factor of
+ten). Typical values for offset are, in fact, C<0> or something between
+C<0> and C<interval>, which is also the recommended range.
Note also that there is an upper limit to how often a timer can fire (CPU
speed for example), so if C<interval> is very small then timing stability
@@ -2302,7 +2417,8 @@ and unblock them in an C<ev_prepare> watcher.
Both the signal mask (C<sigprocmask>) and the signal disposition
(C<sigaction>) are unspecified after starting a signal watcher (and after
stopping it again), that is, libev might or might not block the signal,
-and might or might not set or restore the installed signal handler.
+and might or might not set or restore the installed signal handler (but
+see C<EVFLAG_NOSIGMASK>).
While this does not matter for the signal disposition (libev never
sets signals to C<SIG_IGN>, so handlers will be reset to C<SIG_DFL> on
@@ -3183,7 +3299,7 @@ cleanup functions are called.
=head2 C<ev_async> - how to wake up an event loop
-In general, you cannot use an C<ev_run> from multiple threads or other
+In general, you cannot use an C<ev_loop> from multiple threads or other
asynchronous sources such as signal handlers (as opposed to multiple event
loops - those are of course safe to use in different threads).
@@ -3200,9 +3316,6 @@ of "global async watchers" by using a watcher on an otherwise unused
signal, and C<ev_feed_signal> to signal this watcher from another thread,
even without knowing which loop owns the signal.
-Unlike C<ev_signal> watchers, C<ev_async> works with any event loop, not
-just the default loop.
-
=head3 Queueing
C<ev_async> does not support queueing of data in any way. The reason
@@ -3303,19 +3416,24 @@ trust me.
=item ev_async_send (loop, ev_async *)
Sends/signals/activates the given C<ev_async> watcher, that is, feeds
-an C<EV_ASYNC> event on the watcher into the event loop. Unlike
-C<ev_feed_event>, this call is safe to do from other threads, signal or
-similar contexts (see the discussion of C<EV_ATOMIC_T> in the embedding
-section below on what exactly this means).
+an C<EV_ASYNC> event on the watcher into the event loop, and instantly
+returns.
+
+Unlike C<ev_feed_event>, this call is safe to do from other threads,
+signal or similar contexts (see the discussion of C<EV_ATOMIC_T> in the
+embedding section below on what exactly this means).
Note that, as with other watchers in libev, multiple events might get
-compressed into a single callback invocation (another way to look at this
-is that C<ev_async> watchers are level-triggered, set on C<ev_async_send>,
-reset when the event loop detects that).
+compressed into a single callback invocation (another way to look at
+this is that C<ev_async> watchers are level-triggered: they are set on
+C<ev_async_send>, reset when the event loop detects that).
-This call incurs the overhead of a system call only once per event loop
-iteration, so while the overhead might be noticeable, it doesn't apply to
-repeated calls to C<ev_async_send> for the same event loop.
+This call incurs the overhead of at most one extra system call per event
+loop iteration, if the event loop is blocked, and no syscall at all if
+the event loop (or your program) is processing events. That means that
+repeated calls are basically free (there is no need to avoid calls for
+performance reasons) and that the overhead becomes smaller (typically
+zero) under load.
=item bool = ev_async_pending (ev_async *)
@@ -3380,7 +3498,7 @@ Example: wait up to ten seconds for data to appear on STDIN_FILENO.
=item ev_feed_fd_event (loop, int fd, int revents)
Feed an event on the given fd, as if a file descriptor backend detected
-the given events it.
+the given events.
=item ev_feed_signal_event (loop, int signum)
@@ -3464,6 +3582,46 @@ real programmers):
(((char *)w) - offsetof (struct my_biggy, t2));
}
+=head2 AVOIDING FINISHING BEFORE RETURNING
+
+Often you have structures like this in event-based programs:
+
+ callback ()
+ {
+ free (request);
+ }
+
+ request = start_new_request (..., callback);
+
+The intent is to start some "lengthy" operation. The C<request> could be
+used to cancel the operation, or do other things with it.
+
+It's not uncommon to have code paths in C<start_new_request> that
+immediately invoke the callback, for example, to report errors. Or you add
+some caching layer that finds that it can skip the lengthy aspects of the
+operation and simply invoke the callback with the result.
+
+The problem here is that this will happen I<before> C<start_new_request>
+has returned, so C<request> is not set.
+
+Even if you pass the request by some safer means to the callback, you
+might want to do something to the request after starting it, such as
+canceling it, which probably isn't working so well when the callback has
+already been invoked.
+
+A common way around all these issues is to make sure that
+C<start_new_request> I<always> returns before the callback is invoked. If
+C<start_new_request> immediately knows the result, it can artificially
+delay invoking the callback by e.g. using a C<prepare> or C<idle> watcher
+for example, or more sneakily, by reusing an existing (stopped) watcher
+and pushing it into the pending queue:
+
+ ev_set_cb (watcher, callback);
+ ev_feed_event (EV_A_ watcher, 0);
+
+This way, C<start_new_request> can safely return before the callback is
+invoked, while not delaying callback invocation too much.
+
=head2 MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS
Often (especially in GUI toolkits) there are places where you have
@@ -3486,7 +3644,7 @@ triggered, using C<EVRUN_ONCE>:
while (!exit_main_loop)
ev_run (EV_DEFAULT_ EVRUN_ONCE);
- // in a model watcher
+ // in a modal watcher
int exit_nested_loop = 0;
while (!exit_nested_loop)
@@ -3542,7 +3700,7 @@ First, you need to associate some data with the event loop:
ev_set_invoke_pending_cb (EV_A_ l_invoke);
ev_set_loop_release_cb (EV_A_ l_release, l_acquire);
- // then create the thread running ev_loop
+ // then create the thread running ev_run
pthread_create (&u->tid, 0, l_run, EV_A);
}
@@ -3676,7 +3834,7 @@ called):
That basically suspends the coroutine inside C<wait_for_event> and
continues the libev coroutine, which, when appropriate, switches back to
-this or any other coroutine. I am sure if you sue this your own :)
+this or any other coroutine.
You can do similar tricks if you have, say, threads with an event queue -
instead of storing a coroutine, you store the queue object and instead of
@@ -3779,7 +3937,7 @@ Aliases to the same types/functions as with the C<ev_> prefix.
For each C<ev_TYPE> watcher in F<ev.h> there is a corresponding class of
the same name in the C<ev> namespace, with the exception of C<ev_signal>
which is called C<ev::sig> to avoid clashes with the C<signal> macro
-defines by many implementations.
+defined by many implementations.
All of those classes have these methods:
@@ -3922,7 +4080,7 @@ watchers in the constructor.
class myclass
{
ev::io io ; void io_cb (ev::io &w, int revents);
- ev::io2 io2 ; void io2_cb (ev::io &w, int revents);
+ ev::io io2 ; void io2_cb (ev::io &w, int revents);
ev::idle idle; void idle_cb (ev::idle &w, int revents);
myclass (int fd)
@@ -3983,7 +4141,7 @@ L<http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hlibev>.
=item D
Leandro Lucarella has written a D language binding (F<ev.d>) for libev, to
-be found at L<http://proj.llucax.com.ar/wiki/evd>.
+be found at L<http://www.llucax.com.ar/proj/ev.d/index.html>.
=item Ocaml
@@ -4041,7 +4199,11 @@ suitable for use with C<EV_A>.
=item C<EV_DEFAULT>, C<EV_DEFAULT_>
Similar to the other two macros, this gives you the value of the default
-loop, if multiple loops are supported ("ev loop default").
+loop, if multiple loops are supported ("ev loop default"). The default loop
+will be initialised if it isn't already initialised.
+
+For non-multiplicity builds, these macros do nothing, so you always have
+to initialise the loop somewhere.
=item C<EV_DEFAULT_UC>, C<EV_DEFAULT_UC_>
@@ -4197,6 +4359,15 @@ F<event.h> that are not directly supported by the libev core alone.
In standalone mode, libev will still try to automatically deduce the
configuration, but has to be more conservative.
+=item EV_USE_FLOOR
+
+If defined to be C<1>, libev will use the C<floor ()> function for its
+periodic reschedule calculations, otherwise libev will fall back on a
+portable (slower) implementation. If you enable this, you usually have to
+link against libm or something equivalent. Enabling this when the C<floor>
+function is not available will fail, so the safe default is to not enable
+this.
+
=item EV_USE_MONOTONIC
If defined to be C<1>, libev will try to detect the availability of the
@@ -4335,16 +4506,32 @@ interface to speed up C<ev_stat> watchers. Its actual availability will
be detected at runtime. If undefined, it will be enabled if the headers
indicate GNU/Linux + Glibc 2.4 or newer, otherwise disabled.
+=item EV_NO_SMP
+
+If defined to be C<1>, libev will assume that memory is always coherent
+between threads, that is, threads can be used, but threads never run on
+different cpus (or different cpu cores). This reduces dependencies
+and makes libev faster.
+
+=item EV_NO_THREADS
+
+If defined to be C<1>, libev will assume that it will never be called
+from different threads, which is a stronger assumption than C<EV_NO_SMP>,
+above. This reduces dependencies and makes libev faster.
+
=item EV_ATOMIC_T
Libev requires an integer type (suitable for storing C<0> or C<1>) whose
-access is atomic with respect to other threads or signal contexts. No such
-type is easily found in the C language, so you can provide your own type
-that you know is safe for your purposes. It is used both for signal handler "locking"
-as well as for signal and thread safety in C<ev_async> watchers.
+access is atomic and serialised with respect to other threads or signal
+contexts. No such type is easily found in the C language, so you can
+provide your own type that you know is safe for your purposes. It is used
+both for signal handler "locking" as well as for signal and thread safety
+in C<ev_async> watchers.
In the absence of this define, libev will use C<sig_atomic_t volatile>
-(from F<signal.h>), which is usually good enough on most platforms.
+(from F<signal.h>), which is usually good enough on most platforms,
+although strictly speaking using a type that also implies a memory fence
+is required.
=item EV_H (h)
@@ -4378,6 +4565,10 @@ additional independent event loops. Otherwise there will be no support
for multiple event loops and there is no first event loop pointer
argument. Instead, all functions act on the single default loop.
+Note that C<EV_DEFAULT> and C<EV_DEFAULT_> will no longer provide a
+default loop when multiplicity is switched off - you always have to
+initialise the loop manually in this case.
+
=item EV_MINPRI
=item EV_MAXPRI
@@ -4485,6 +4676,20 @@ when you use C<-Wl,--gc-sections -ffunction-sections>) functions unused by
your program might be left out as well - a binary starting a timer and an
I/O watcher then might come out at only 5Kb.
+=item EV_API_STATIC
+
+If this symbol is defined (by default it is not), then all identifiers
+will have static linkage. This means that libev will not export any
+identifiers, and you cannot link against libev anymore. This can be useful
+when you embed libev, only want to use libev functions in a single file,
+and do not want its identifiers to be visible.
+
+To use this, define C<EV_API_STATIC> and include F<ev.c> in the file that
+wants to use libev.
+
+This option only works when libev is compiled with a C compiler, as C++
+doesn't support the required declaration syntax.
+
=item EV_AVOID_STDIO
If this is set to C<1> at compiletime, then libev will avoid using stdio
@@ -4873,7 +5078,7 @@ model. Libev still offers limited functionality on this platform in
the form of the C<EVBACKEND_SELECT> backend, and only supports socket
descriptors. This only applies when using Win32 natively, not when using
e.g. cygwin. Actually, it only applies to the microsofts own compilers,
-as every compielr comes with a slightly differently broken/incompatible
+as every compiler comes with a slightly differently broken/incompatible
environment.
Lifting these limitations would basically require the full
@@ -5016,8 +5221,12 @@ The type C<double> is used to represent timestamps. It is required to
have at least 51 bits of mantissa (and 9 bits of exponent), which is
good enough for at least into the year 4000 with millisecond accuracy
(the design goal for libev). This requirement is overfulfilled by
-implementations using IEEE 754, which is basically all existing ones. With
-IEEE 754 doubles, you get microsecond accuracy until at least 2200.
+implementations using IEEE 754, which is basically all existing ones.
+
+With IEEE 754 doubles, you get microsecond accuracy until at least the
+year 2255 (and millisecond accuracy till the year 287396 - by then, libev
+is either obsolete or somebody patched it to use C<long double> or
+something like that, just kidding).
=back
@@ -5089,8 +5298,9 @@ watchers becomes O(1) with respect to priority handling.
=item Processing signals: O(max_signal_number)
Sending involves a system call I<iff> there were no other C<ev_async_send>
-calls in the current loop iteration. Checking for async and signal events
-involves iterating over all running async watchers or all signal numbers.
+calls in the current loop iteration and the loop is currently
+blocked. Checking for async and signal events involves iterating over all
+running async watchers or all signal numbers.
=back
@@ -5217,7 +5427,7 @@ The physical time that is observed. It is apparently strictly monotonic :)
=item wall-clock time
The time and date as shown on clocks. Unlike real time, it can actually
-be wrong and jump forwards and backwards, e.g. when the you adjust your
+be wrong and jump forwards and backwards, e.g. when you adjust your
clock.
=item watcher
@@ -5230,5 +5440,5 @@ to be started (attached to an event loop) before they can receive events.
=head1 AUTHOR
Marc Lehmann <libev@schmorp.de>, with repeated corrections by Mikael
-Magnusson and Emanuele Giaquinta.
+Magnusson and Emanuele Giaquinta, and minor corrections by many others.
diff --git a/libev/ev_epoll.c b/libev/ev_epoll.c
index d0caa93..b4e02c2 100644
--- a/libev/ev_epoll.c
+++ b/libev/ev_epoll.c
@@ -6,14 +6,14 @@
*
* 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
@@ -144,11 +144,13 @@ epoll_poll (EV_P_ ev_tstamp timeout)
int i;
int eventcnt;
+ if (expect_false (epoll_epermcnt))
+ timeout = 0.;
+
/* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */
/* the default libev max wait time, however. */
EV_RELEASE_CB;
- eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax,
- epoll_epermcnt ? 0 : (int)ceil (timeout * 1000.));
+ eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, timeout * 1e3);
EV_ACQUIRE_CB;
if (expect_false (eventcnt < 0))
@@ -168,8 +170,12 @@ epoll_poll (EV_P_ ev_tstamp timeout)
int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0)
| (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0);
- /* check for spurious notification */
- /* we assume that fd is always in range, as we never shrink the anfds array */
+ /*
+ * check for spurious notification.
+ * this only finds spurious notifications on egen updates
+ * other spurious notifications will be found by epoll_ctl, below
+ * we assume that fd is always in range, as we never shrink the anfds array
+ */
if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32)))
{
/* recreate kernel state */
@@ -181,8 +187,15 @@ epoll_poll (EV_P_ ev_tstamp timeout)
{
anfds [fd].emask = want;
- /* we received an event but are not interested in it, try mod or del */
- /* I don't think we ever need MOD, but let's handle it anyways */
+ /*
+ * we received an event but are not interested in it, try mod or del
+ * this often happens because we optimistically do not unregister fds
+ * when we are no longer interested in them, but also when we get spurious
+ * notifications for fds from another process. this is partially handled
+ * above with the gencounter check (== our fd is not the event fd), and
+ * partially here, when epoll_ctl returns an error (== a child has the fd
+ * but we closed it).
+ */
ev->events = (want & EV_READ ? EPOLLIN : 0)
| (want & EV_WRITE ? EPOLLOUT : 0);
@@ -225,7 +238,7 @@ epoll_init (EV_P_ int flags)
#ifdef EPOLL_CLOEXEC
backend_fd = epoll_create1 (EPOLL_CLOEXEC);
- if (backend_fd <= 0)
+ if (backend_fd < 0)
#endif
backend_fd = epoll_create (256);
@@ -234,9 +247,9 @@ epoll_init (EV_P_ int flags)
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
- backend_fudge = 0.; /* kernel sources seem to indicate this to be zero */
- backend_modify = epoll_modify;
- backend_poll = epoll_poll;
+ backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
+ backend_modify = epoll_modify;
+ backend_poll = epoll_poll;
epoll_eventmax = 64; /* initial number of events receivable per poll */
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);
diff --git a/libev/ev_kqueue.c b/libev/ev_kqueue.c
index 0d809f5..91b85ed 100644
--- a/libev/ev_kqueue.c
+++ b/libev/ev_kqueue.c
@@ -1,19 +1,19 @@
/*
* libev kqueue backend
*
- * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
* 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
@@ -103,12 +103,12 @@ kqueue_poll (EV_P_ ev_tstamp timeout)
kqueue_changecnt = 0;
if (expect_false (res < 0))
- {
+ {
if (errno != EINTR)
ev_syserr ("(libev) kevent");
return;
- }
+ }
for (i = 0; i < res; ++i)
{
@@ -161,9 +161,9 @@ kqueue_init (EV_P_ int flags)
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
- backend_fudge = 0.;
- backend_modify = kqueue_modify;
- backend_poll = kqueue_poll;
+ backend_mintime = 1e-9; /* apparently, they did the right thing in freebsd */
+ backend_modify = kqueue_modify;
+ backend_poll = kqueue_poll;
kqueue_eventmax = 64; /* initial number of events receivable per poll */
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
diff --git a/libev/ev_poll.c b/libev/ev_poll.c
index 81e4b53..4832351 100644
--- a/libev/ev_poll.c
+++ b/libev/ev_poll.c
@@ -1,19 +1,19 @@
/*
* libev poll fd activity backend
*
- * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
* 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
@@ -92,7 +92,7 @@ poll_poll (EV_P_ ev_tstamp timeout)
int res;
EV_RELEASE_CB;
- res = poll (polls, pollcnt, (int)ceil (timeout * 1000.));
+ res = poll (polls, pollcnt, timeout * 1e3);
EV_ACQUIRE_CB;
if (expect_false (res < 0))
@@ -129,9 +129,9 @@ poll_poll (EV_P_ ev_tstamp timeout)
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;
+ backend_mintime = 1e-3;
+ backend_modify = poll_modify;
+ backend_poll = poll_poll;
pollidxs = 0; pollidxmax = 0;
polls = 0; pollmax = 0; pollcnt = 0;
diff --git a/libev/ev_port.c b/libev/ev_port.c
index 9044ef7..9368501 100644
--- a/libev/ev_port.c
+++ b/libev/ev_port.c
@@ -1,19 +1,19 @@
/*
* libev solaris event port backend
*
- * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
* 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
@@ -147,9 +147,15 @@ port_init (EV_P_ int flags)
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
- backend_fudge = 1e-3; /* needed to compensate for port_getn returning early */
- backend_modify = port_modify;
- backend_poll = port_poll;
+ /* if my reading of the opensolaris kernel sources are correct, then
+ * opensolaris does something very stupid: it checks if the time has already
+ * elapsed and doesn't round up if that is the case,m otherwise it DOES round
+ * up. Since we can't know what the case is, we need to guess by using a
+ * "large enough" timeout. Normally, 1e-9 would be correct.
+ */
+ backend_mintime = 1e-3; /* needed to compensate for port_getn returning early */
+ backend_modify = port_modify;
+ backend_poll = port_poll;
port_eventmax = 64; /* initial number of events receivable per poll */
port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax);
diff --git a/libev/ev_select.c b/libev/ev_select.c
index 76ffa86..f38d6ca 100644
--- a/libev/ev_select.c
+++ b/libev/ev_select.c
@@ -1,19 +1,19 @@
/*
* libev select fd activity backend
*
- * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
* 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
@@ -39,8 +39,11 @@
#ifndef _WIN32
/* for unix systems */
-# include <sys/select.h>
# include <inttypes.h>
+# ifndef __hpux
+/* for REAL unix systems */
+# include <sys/select.h>
+# endif
#endif
#ifndef EV_SELECT_USE_FD_SET
@@ -192,7 +195,12 @@ select_poll (EV_P_ ev_tstamp timeout)
*/
if (errno == EINVAL)
{
- ev_sleep (timeout);
+ if (timeout)
+ {
+ unsigned long ms = timeout * 1e3;
+ Sleep (ms ? ms : 1);
+ }
+
return;
}
#endif
@@ -266,9 +274,9 @@ select_poll (EV_P_ ev_tstamp timeout)
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;
+ backend_mintime = 1e-6;
+ 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);
@@ -280,10 +288,10 @@ select_init (EV_P_ int flags)
#endif
#else
vec_max = 0;
- vec_ri = 0;
- vec_ro = 0;
- vec_wi = 0;
- vec_wo = 0;
+ vec_ri = 0;
+ vec_ro = 0;
+ vec_wi = 0;
+ vec_wo = 0;
#ifdef _WIN32
vec_eo = 0;
#endif
@@ -304,4 +312,3 @@ select_destroy (EV_P)
#endif
}
-
diff --git a/libev/ev_vars.h b/libev/ev_vars.h
index 17d77c8..9f7acb6 100644
--- a/libev/ev_vars.h
+++ b/libev/ev_vars.h
@@ -6,14 +6,14 @@
*
* 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
@@ -51,7 +51,7 @@ 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 */
+VARx(ev_tstamp, backend_mintime) /* 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))
@@ -73,6 +73,8 @@ VARx(int, evfd)
#endif
VAR (evpipe, int evpipe [2])
VARx(ev_io, pipe_w)
+VARx(EV_ATOMIC_T, pipe_write_wanted)
+VARx(EV_ATOMIC_T, pipe_write_skipped)
#if !defined(_WIN32) || EV_GENWRAP
VARx(pid_t, curpid)
@@ -180,7 +182,6 @@ 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)
diff --git a/libev/ev_win32.c b/libev/ev_win32.c
index ee60ae6..338886e 100644
--- a/libev/ev_win32.c
+++ b/libev/ev_win32.c
@@ -6,14 +6,14 @@
*
* 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
@@ -46,7 +46,7 @@
/* 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;
+volatile double SIGFPE_REQ = 0.0f;
/* oh, the humanity! */
static int
@@ -59,7 +59,7 @@ ev_pipe (int filedes [2])
SOCKET listener;
SOCKET sock [2] = { -1, -1 };
- if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
return -1;
addr.sin_family = AF_INET;
@@ -75,7 +75,7 @@ ev_pipe (int filedes [2])
if (listen (listener, 1))
goto fail;
- if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
goto fail;
if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
diff --git a/libev/ev_wrap.h b/libev/ev_wrap.h
index 2c195c5..36edbd2 100644
--- a/libev/ev_wrap.h
+++ b/libev/ev_wrap.h
@@ -10,7 +10,7 @@
#define activecnt ((loop)->activecnt)
#define loop_done ((loop)->loop_done)
#define backend_fd ((loop)->backend_fd)
-#define backend_fudge ((loop)->backend_fudge)
+#define backend_mintime ((loop)->backend_mintime)
#define backend_modify ((loop)->backend_modify)
#define backend_poll ((loop)->backend_poll)
#define anfds ((loop)->anfds)
@@ -25,6 +25,8 @@
#define evfd ((loop)->evfd)
#define evpipe ((loop)->evpipe)
#define pipe_w ((loop)->pipe_w)
+#define pipe_write_wanted ((loop)->pipe_write_wanted)
+#define pipe_write_skipped ((loop)->pipe_write_skipped)
#define curpid ((loop)->curpid)
#define postfork ((loop)->postfork)
#define vec_ri ((loop)->vec_ri)
@@ -85,7 +87,6 @@
#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)
@@ -107,7 +108,7 @@
#undef activecnt
#undef loop_done
#undef backend_fd
-#undef backend_fudge
+#undef backend_mintime
#undef backend_modify
#undef backend_poll
#undef anfds
@@ -122,6 +123,8 @@
#undef evfd
#undef evpipe
#undef pipe_w
+#undef pipe_write_wanted
+#undef pipe_write_skipped
#undef curpid
#undef postfork
#undef vec_ri
@@ -182,7 +185,6 @@
#undef fs_2625
#undef fs_hash
#undef sig_pending
-#undef nosigmask
#undef sigfd
#undef sigfd_w
#undef sigfd_set
diff --git a/libev/event.c b/libev/event.c
index 579423f..aaf6d53 100644
--- a/libev/event.c
+++ b/libev/event.c
@@ -6,14 +6,14 @@
*
* 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
diff --git a/libev/event.h b/libev/event.h
index 6411fb6..10ff05a 100644
--- a/libev/event.h
+++ b/libev/event.h
@@ -6,14 +6,14 @@
*
* 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
diff --git a/libev/libev.m4 b/libev/libev.m4
index 0930c0c..6fdb13f 100644
--- a/libev/libev.m4
+++ b/libev/libev.m4
@@ -6,7 +6,7 @@ AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/select.
AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd signalfd)
-AC_CHECK_FUNC(clock_gettime, [], [
+AC_CHECK_FUNCS(clock_gettime, [], [
dnl on linux, try syscall wrapper first
if test $(uname) = Linux; then
AC_MSG_CHECKING(for clock_gettime syscall)
@@ -16,7 +16,7 @@ AC_CHECK_FUNC(clock_gettime, [], [
#include <time.h>],
[struct timespec ts; int status = syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts)])],
[ac_have_clock_syscall=1
- AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, "use syscall interface for clock_gettime")
+ AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, Define to 1 to use the syscall interface for clock_gettime)
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
fi
@@ -27,7 +27,7 @@ AC_CHECK_FUNC(clock_gettime, [], [
fi
])
-AC_CHECK_FUNC(nanosleep, [], [
+AC_CHECK_FUNCS(nanosleep, [], [
if test -z "$LIBEV_M4_AVOID_LIBRT"; then
AC_CHECK_LIB(rt, nanosleep)
unset ac_cv_func_nanosleep
@@ -35,5 +35,8 @@ AC_CHECK_FUNC(nanosleep, [], [
fi
])
-AC_CHECK_LIB(m, ceil)
+if test -z "$LIBEV_M4_AVOID_LIBM"; then
+ LIBM=m
+fi
+AC_SEARCH_LIBS(floor, $LIBM, [AC_DEFINE(HAVE_FLOOR, 1, Define to 1 if the floor function is available)])