diff --git a/deps/libev/Changes b/deps/libev/Changes index 25b9adc787..af902a6973 100644 --- a/deps/libev/Changes +++ b/deps/libev/Changes @@ -1,5 +1,30 @@ Revision history for libev, a high-performance and full-featured event loop. +3.7 Fri Jul 17 16:36:32 CEST 2009 + - ev_unloop and ev_loop wrongly used a global variable to exit loops, + instead of using a per-loop variable (bug caught by accident...). + - the ev_set_io_collect_interval interpretation has changed. + - add new functionality: ev_set_userdata, ev_userdata, + ev_set_invoke_pending_cb, ev_set_loop_release_cb, + ev_invoke_pending, together with a long example about thread + locking. + - add ev_timer_remaining (as requested by Denis F. Latypoff). + - add ev_loop_depth. + - calling ev_unloop in fork/prepare watchers will no longer poll + for new events. + - Denis F. Latypoff corrected many typos in example code snippets. + - honor autoconf detection of EV_USE_CLOCK_SYSCALL, also double- + check that the syscall number is available before trying to + use it (reported by ry@tinyclouds). + - use GetSystemTimeAsFileTime instead of _timeb on windows, for + slightly higher accuracy. + - properly declare ev_loop_verify and ev_now_update even when + !EV_MULTIPLICITY. + - do not compile in any priority code when EV_MAXPRI == EV_MINPRI. + - support EV_MINIMAL==2 for a reduced API. + - actually 0-initialise struct sigaction when installing signals. + - add section on hibernate and stopped processes to ev_timer docs. + 3.6 Tue Apr 28 02:49:30 CEST 2009 - multiple timers becoming ready within an event loop iteration will be invoked in the "correct" order now. diff --git a/deps/libev/configure b/deps/libev/configure index 0bae1caa24..792c9dcf89 100755 --- a/deps/libev/configure +++ b/deps/libev/configure @@ -2207,7 +2207,7 @@ fi # Define the identity of the package. PACKAGE=libev - VERSION=3.6 + VERSION=3.7 cat >>confdefs.h <<_ACEOF @@ -2348,8 +2348,7 @@ INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" # some platforms. - -ac_config_headers="$ac_config_headers config.h" + ac_config_headers="$ac_config_headers config.h" { echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6; } @@ -4350,7 +4349,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4353 "configure"' > conftest.$ac_ext + echo '#line 4352 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7396,11 +7395,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:7399: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7398: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7403: \$? = $ac_status" >&5 + echo "$as_me:7402: \$? = $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. @@ -7686,11 +7685,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:7689: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7688: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7693: \$? = $ac_status" >&5 + echo "$as_me:7692: \$? = $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. @@ -7790,11 +7789,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:7793: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7792: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7797: \$? = $ac_status" >&5 + echo "$as_me:7796: \$? = $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 @@ -10167,7 +10166,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12670: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12675: \$? = $ac_status" >&5 + echo "$as_me:12674: \$? = $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. @@ -12772,11 +12771,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:12775: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12774: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12779: \$? = $ac_status" >&5 + echo "$as_me:12778: \$? = $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 @@ -14370,11 +14369,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:14373: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14372: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14377: \$? = $ac_status" >&5 + echo "$as_me:14376: \$? = $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. @@ -14474,11 +14473,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:14477: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14476: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14481: \$? = $ac_status" >&5 + echo "$as_me:14480: \$? = $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 @@ -16694,11 +16693,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:16697: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16696: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16701: \$? = $ac_status" >&5 + echo "$as_me:16700: \$? = $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. @@ -16984,11 +16983,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:16987: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16986: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16991: \$? = $ac_status" >&5 + echo "$as_me:16990: \$? = $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. @@ -17088,11 +17087,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:17091: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17090: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:17095: \$? = $ac_status" >&5 + echo "$as_me:17094: \$? = $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 diff --git a/deps/libev/configure.ac b/deps/libev/configure.ac index 37df5195e1..3d0caa411c 100644 --- a/deps/libev/configure.ac +++ b/deps/libev/configure.ac @@ -1,7 +1,7 @@ AC_INIT AC_CONFIG_SRCDIR([ev_epoll.c]) -AM_INIT_AUTOMAKE(libev,3.6) +AM_INIT_AUTOMAKE(libev,3.7) dnl also update ev.h! AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE diff --git a/deps/libev/ev++.h b/deps/libev/ev++.h index f1b4c6ffd2..4cec6993ec 100644 --- a/deps/libev/ev++.h +++ b/deps/libev/ev++.h @@ -207,11 +207,6 @@ namespace ev { #endif } - unsigned int count () const throw () - { - return ev_loop_count (EV_AX); - } - unsigned int backend () const throw () { return ev_backend (EV_AX); @@ -232,6 +227,17 @@ namespace ev { ev_unref (EV_AX); } +#if EV_MINIMAL < 2 + unsigned int count () const throw () + { + return ev_loop_count (EV_AX); + } + + unsigned int depth () const throw () + { + return ev_loop_depth (EV_AX); + } + void set_io_collect_interval (tstamp interval) throw () { ev_set_io_collect_interval (EV_AX_ interval); @@ -241,6 +247,7 @@ namespace ev { { ev_set_timeout_collect_interval (EV_AX_ interval); } +#endif // function callback void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void *arg = 0) throw () diff --git a/deps/libev/ev.3 b/deps/libev/ev.3 index e87b7f7897..ea523010fa 100644 --- a/deps/libev/ev.3 +++ b/deps/libev/ev.3 @@ -1,15 +1,7 @@ -.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.05) +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) .\" .\" Standard preamble: .\" ======================================================================== -.de Sh \" Subsection heading -.br -.if t .Sp -.ne 5 -.PP -\fB\\$1\fR -.PP -.. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp @@ -53,7 +45,7 @@ .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ @@ -132,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "LIBEV 3" -.TH LIBEV 3 "2009-04-25" "libev-3.6" "libev - high performance full featured event loop" +.TH LIBEV 3 "2009-07-15" "libev-3.7" "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 @@ -144,7 +136,7 @@ libev \- a high performance full\-featured event loop written in C .Vb 1 \& #include .Ve -.Sh "\s-1EXAMPLE\s0 \s-1PROGRAM\s0" +.SS "\s-1EXAMPLE\s0 \s-1PROGRAM\s0" .IX Subsection "EXAMPLE PROGRAM" .Vb 2 \& // a single header file is required @@ -232,7 +224,7 @@ You register interest in certain events by registering so-called \fIevent watchers\fR, which are relatively small C structures you initialise with the details of the event, and then hand it over to libev by \fIstarting\fR the watcher. -.Sh "\s-1FEATURES\s0" +.SS "\s-1FEATURES\s0" .IX Subsection "FEATURES" Libev supports \f(CW\*(C`select\*(C'\fR, \f(CW\*(C`poll\*(C'\fR, the Linux-specific \f(CW\*(C`epoll\*(C'\fR, the BSD-specific \f(CW\*(C`kqueue\*(C'\fR and the Solaris-specific event port mechanisms @@ -246,9 +238,9 @@ file watchers (\f(CW\*(C`ev_stat\*(C'\fR) and even limited support for fork even (\f(CW\*(C`ev_fork\*(C'\fR). .PP It also is quite fast (see this -benchmark comparing it to libevent + comparing it to libevent for example). -.Sh "\s-1CONVENTIONS\s0" +.SS "\s-1CONVENTIONS\s0" .IX Subsection "CONVENTIONS" Libev is very configurable. In this manual the default (and most common) configuration will be described, which supports multiple event loops. For @@ -257,7 +249,7 @@ more info about various configuration options please have a look at for multiple event loops, then all functions taking an initial argument of name \f(CW\*(C`loop\*(C'\fR (which is always of type \f(CW\*(C`ev_loop *\*(C'\fR) will not have this argument. -.Sh "\s-1TIME\s0 \s-1REPRESENTATION\s0" +.SS "\s-1TIME\s0 \s-1REPRESENTATION\s0" .IX Subsection "TIME REPRESENTATION" Libev represents time as a single floating point number, representing the (fractional) number of seconds since the (\s-1POSIX\s0) epoch (somewhere @@ -751,6 +743,17 @@ happily wraps around with enough iterations. This value can sometimes be useful as a generation counter of sorts (it \&\*(L"ticks\*(R" the number of loop iterations), as it roughly corresponds with \&\f(CW\*(C`ev_prepare\*(C'\fR and \f(CW\*(C`ev_check\*(C'\fR calls. +.IP "unsigned int ev_loop_depth (loop)" 4 +.IX Item "unsigned int ev_loop_depth (loop)" +Returns the number of times \f(CW\*(C`ev_loop\*(C'\fR was entered minus the number of +times \f(CW\*(C`ev_loop\*(C'\fR was exited, in other words, the recursion depth. +.Sp +Outside \f(CW\*(C`ev_loop\*(C'\fR, this number is zero. In a callback, this number is +\&\f(CW1\fR, unless \f(CW\*(C`ev_loop\*(C'\fR was invoked recursively (or from another thread), +in which case it is higher. +.Sp +Leaving \f(CW\*(C`ev_loop\*(C'\fR abnormally (setjmp/longjmp, cancelling the thread +etc.), doesn't count as exit. .IP "unsigned int ev_backend (loop)" 4 .IX Item "unsigned int ev_backend (loop)" Returns one of the \f(CW\*(C`EVBACKEND_*\*(C'\fR flags indicating the event backend in @@ -948,7 +951,9 @@ 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 -introduce an additional \f(CW\*(C`ev_sleep ()\*(C'\fR call into most loop iterations. +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. .Sp Likewise, by setting a higher \fItimeout collect interval\fR you allow libev to spend more time collecting timeouts, at the expense of increased @@ -960,7 +965,11 @@ Many (busy) programs can usually benefit by setting the I/O collect interval to a value near \f(CW0.1\fR or so, which is often enough for interactive servers (of course not for games), likewise for timeouts. It usually doesn't make much sense to set it to a lower value than \f(CW0.01\fR, -as this approaches the timing granularity of most systems. +as this approaches the timing granularity of most systems. Note that if +you do transactions with the outside world and you can't increase the +parallelity, then this setting will limit your transaction rate (if you +need to poll once per transaction and the I/O collect interval is 0.01, +then you can't do more than 100 transations per second). .Sp Setting the \fItimeout collect interval\fR can improve the opportunity for saving power, as the program will \*(L"bundle\*(R" timer callback invocations that @@ -968,6 +977,76 @@ are \*(L"near\*(R" in time together, by delaying some, thus reducing the number times the process sleeps and wakes up again. Another useful technique to reduce iterations/wake\-ups is to use \f(CW\*(C`ev_periodic\*(C'\fR watchers and make sure they fire on, say, one-second boundaries only. +.Sp +Example: we only need 0.1s timeout granularity, and we wish not to poll +more often than 100 times per second: +.Sp +.Vb 2 +\& ev_set_timeout_collect_interval (EV_DEFAULT_UC_ 0.1); +\& ev_set_io_collect_interval (EV_DEFAULT_UC_ 0.01); +.Ve +.IP "ev_invoke_pending (loop)" 4 +.IX Item "ev_invoke_pending (loop)" +This call will simply invoke all pending watchers while resetting their +pending state. Normally, \f(CW\*(C`ev_loop\*(C'\fR does this automatically when required, +but when overriding the invoke callback this call comes handy. +.IP "int ev_pending_count (loop)" 4 +.IX Item "int ev_pending_count (loop)" +Returns the number of pending watchers \- zero indicates that no watchers +are pending. +.IP "ev_set_invoke_pending_cb (loop, void (*invoke_pending_cb)(\s-1EV_P\s0))" 4 +.IX Item "ev_set_invoke_pending_cb (loop, void (*invoke_pending_cb)(EV_P))" +This overrides the invoke pending functionality of the loop: Instead of +invoking all pending watchers when there are any, \f(CW\*(C`ev_loop\*(C'\fR will call +this callback instead. This is useful, for example, when you want to +invoke the actual watchers inside another context (another thread etc.). +.Sp +If you want to reset the callback, use \f(CW\*(C`ev_invoke_pending\*(C'\fR as new +callback. +.IP "ev_set_loop_release_cb (loop, void (*release)(\s-1EV_P\s0), void (*acquire)(\s-1EV_P\s0))" 4 +.IX Item "ev_set_loop_release_cb (loop, void (*release)(EV_P), void (*acquire)(EV_P))" +Sometimes you want to share the same loop between multiple threads. This +can be done relatively simply by putting mutex_lock/unlock calls around +each call to a libev function. +.Sp +However, \f(CW\*(C`ev_loop\*(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 loop via +\&\f(CW\*(C`ev_unloop\*(C'\fR and \f(CW\*(C`av_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 +suspended waiting for new events, and \f(CW\*(C`acquire\*(C'\fR is called just +afterwards. +.Sp +Ideally, \f(CW\*(C`release\*(C'\fR will just call your mutex_unlock function, and +\&\f(CW\*(C`acquire\*(C'\fR will just call the mutex_lock function again. +.Sp +While event loop modifications are allowed between invocations of +\&\f(CW\*(C`release\*(C'\fR and \f(CW\*(C`acquire\*(C'\fR (that's their only purpose after all), no +modifications done will affect the event loop, i.e. adding watchers will +have no effect on the set of file descriptors being watched, or the time +waited. USe an \f(CW\*(C`ev_async\*(C'\fR watcher to wake up \f(CW\*(C`ev_loop\*(C'\fR when you want it +to take note of any changes you made. +.Sp +In theory, threads executing \f(CW\*(C`ev_loop\*(C'\fR will be async-cancel safe between +invocations of \f(CW\*(C`release\*(C'\fR and \f(CW\*(C`acquire\*(C'\fR. +.Sp +See also the locking example in the \f(CW\*(C`THREADS\*(C'\fR section later in this +document. +.IP "ev_set_userdata (loop, void *data)" 4 +.IX Item "ev_set_userdata (loop, void *data)" +.PD 0 +.IP "ev_userdata (loop)" 4 +.IX Item "ev_userdata (loop)" +.PD +Set and retrieve a single \f(CW\*(C`void *\*(C'\fR associated with a loop. When +\&\f(CW\*(C`ev_set_userdata\*(C'\fR has never been called, then \f(CW\*(C`ev_userdata\*(C'\fR returns +\&\f(CW0.\fR +.Sp +These two functions can be used to associate arbitrary data with a loop, +and are intended solely for the \f(CW\*(C`invoke_pending_cb\*(C'\fR, \f(CW\*(C`release\*(C'\fR and +\&\f(CW\*(C`acquire\*(C'\fR callbacks described above, but of course can be (ab\-)used for +any other purpose as well. .IP "ev_loop_verify (loop)" 4 .IX Item "ev_loop_verify (loop)" This function only does something when \f(CW\*(C`EV_VERIFY\*(C'\fR support has been @@ -1126,7 +1205,7 @@ callbacks is well-written it can just attempt the operation and cope with the error from \fIread()\fR or \fIwrite()\fR. This will not work in multi-threaded programs, though, as the fd could already be closed and reused for another thing, so beware. -.Sh "\s-1GENERIC\s0 \s-1WATCHER\s0 \s-1FUNCTIONS\s0" +.SS "\s-1GENERIC\s0 \s-1WATCHER\s0 \s-1FUNCTIONS\s0" .IX Subsection "GENERIC WATCHER FUNCTIONS" .ie n .IP """ev_init"" (ev_TYPE *watcher, callback)" 4 .el .IP "\f(CWev_init\fR (ev_TYPE *watcher, callback)" 4 @@ -1260,7 +1339,7 @@ watcher isn't pending it does nothing and returns \f(CW0\fR. .Sp Sometimes it can be useful to \*(L"poll\*(R" a watcher instead of waiting for its callback to be invoked, which can be accomplished with this function. -.Sh "\s-1ASSOCIATING\s0 \s-1CUSTOM\s0 \s-1DATA\s0 \s-1WITH\s0 A \s-1WATCHER\s0" +.SS "\s-1ASSOCIATING\s0 \s-1CUSTOM\s0 \s-1DATA\s0 \s-1WITH\s0 A \s-1WATCHER\s0" .IX Subsection "ASSOCIATING CUSTOM DATA WITH A WATCHER" Each watcher has, by default, a member \f(CW\*(C`void *data\*(C'\fR that you can change and read at any time: libev will completely ignore it. This can be used @@ -1321,18 +1400,18 @@ programmers): \& static void \& t1_cb (EV_P_ ev_timer *w, int revents) \& { -\& struct my_biggy big = (struct my_biggy * +\& struct my_biggy big = (struct my_biggy *) \& (((char *)w) \- offsetof (struct my_biggy, t1)); \& } \& \& static void \& t2_cb (EV_P_ ev_timer *w, int revents) \& { -\& struct my_biggy big = (struct my_biggy * +\& struct my_biggy big = (struct my_biggy *) \& (((char *)w) \- offsetof (struct my_biggy, t2)); \& } .Ve -.Sh "\s-1WATCHER\s0 \s-1PRIORITY\s0 \s-1MODELS\s0" +.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 integers that influence the ordering of event callback invocation @@ -1415,7 +1494,7 @@ other events are pending: \& } \& \& static void -\& idle\-cb (EV_P_ ev_idle *w, int revents) +\& idle_cb (EV_P_ ev_idle *w, int revents) \& { \& // actual processing \& read (STDIN_FILENO, ...); @@ -1450,8 +1529,8 @@ means you can expect it to have some sensible content while the watcher is active, but you can also modify it. Modifying it may not do something sensible or take immediate effect (or do anything at all), but libev will not crash or malfunction in any way. -.ie n .Sh """ev_io"" \- is this file descriptor readable or writable?" -.el .Sh "\f(CWev_io\fP \- is this file descriptor readable or writable?" +.ie n .SS """ev_io"" \- is this file descriptor readable or writable?" +.el .SS "\f(CWev_io\fP \- is this file descriptor readable or writable?" .IX Subsection "ev_io - is this file descriptor readable or writable?" I/O watchers check whether a file descriptor is readable or writable in each iteration of the event loop, or, more precisely, when reading @@ -1589,8 +1668,8 @@ attempt to read a whole line in the callback. \& ev_io_start (loop, &stdin_readable); \& ev_loop (loop, 0); .Ve -.ie n .Sh """ev_timer"" \- relative and optionally repeating timeouts" -.el .Sh "\f(CWev_timer\fP \- relative and optionally repeating timeouts" +.ie n .SS """ev_timer"" \- relative and optionally repeating timeouts" +.el .SS "\f(CWev_timer\fP \- relative and optionally repeating timeouts" .IX Subsection "ev_timer - relative and optionally repeating timeouts" Timer watchers are simple relative timers that generate an event after a given time, and optionally repeating in regular intervals after that. @@ -1605,8 +1684,8 @@ 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 with later time-out values (but this is no longer true when a -callback calls \f(CW\*(C`ev_loop\*(C'\fR recursively). +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_loop\*(C'\fR recursively). .PP \fIBe smart about timeouts\fR .IX Subsection "Be smart about timeouts" @@ -1663,7 +1742,7 @@ member and \f(CW\*(C`ev_timer_again\*(C'\fR. At start: .Sp .Vb 3 -\& ev_timer_init (timer, callback); +\& ev_init (timer, callback); \& timer\->repeat = 60.; \& ev_timer_again (loop, timer); .Ve @@ -1742,7 +1821,7 @@ 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: .Sp .Vb 3 -\& ev_timer_init (timer, callback); +\& ev_init (timer, callback); \& last_activity = ev_now (loop); \& callback (loop, timer, EV_TIMEOUT); .Ve @@ -1816,6 +1895,37 @@ 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 problems of suspended animation\fR +.IX Subsection "The special problems of suspended animation" +.PP +When you leave the server world it is quite customary to hit machines that +can suspend/hibernate \- what happens to the clocks during such a suspend? +.PP +Some quick tests made with a Linux 2.6.28 indicate that a suspend freezes +all processes, while the clocks (\f(CW\*(C`times\*(C'\fR, \f(CW\*(C`CLOCK_MONOTONIC\*(C'\fR) continue +to run until the system is suspended, but they will not advance while the +system is suspended. That means, on resume, it will be as if the program +was frozen for a few seconds, but the suspend time will not be counted +towards \f(CW\*(C`ev_timer\*(C'\fR when a monotonic clock source is used. The real time +clock advanced as expected, but if it is used as sole clocksource, then a +long suspend would be detected as a time jump by libev, and timers would +be adjusted accordingly. +.PP +I would not be surprised to see different behaviour in different between +operating systems, \s-1OS\s0 versions or even different hardware. +.PP +The other form of suspend (job control, or sending a \s-1SIGSTOP\s0) will see a +time jump in the monotonic clocks and the realtime clock. If the program +is suspended for a very long time, and monotonic clock sources are in use, +then you can expect \f(CW\*(C`ev_timer\*(C'\fRs to expire as the full suspension time +will be counted towards the timers. When no monotonic clock source is in +use, then libev will again assume a timejump and adjust accordingly. +.PP +It might be beneficial for this latter case to call \f(CW\*(C`ev_suspend\*(C'\fR +and \f(CW\*(C`ev_resume\*(C'\fR in code that handles \f(CW\*(C`SIGTSTP\*(C'\fR, to at least get +deterministic behaviour in this case (you can do nothing against +\&\f(CW\*(C`SIGSTOP\*(C'\fR). +.PP \fIWatcher-Specific Functions and Data Members\fR .IX Subsection "Watcher-Specific Functions and Data Members" .IP "ev_timer_init (ev_timer *, callback, ev_tstamp after, ev_tstamp repeat)" 4 @@ -1849,6 +1959,17 @@ If the timer is repeating, either start it if necessary (with the .Sp This sounds a bit complicated, see \*(L"Be smart about timeouts\*(R", above, for a usage example. +.IP "ev_timer_remaining (loop, ev_timer *)" 4 +.IX Item "ev_timer_remaining (loop, ev_timer *)" +Returns the remaining time until a timer fires. If the timer is active, +then this time is relative to the current event loop time, otherwise it's +the timeout value currently configured. +.Sp +That is, after an \f(CW\*(C`ev_timer_set (w, 5, 7)\*(C'\fR, \f(CW\*(C`ev_timer_remaining\*(C'\fR returns +\&\f(CW5\fR. When the timer is started and one second passes, \f(CW\*(C`ev_timer_remain\*(C'\fR +will return \f(CW4\fR. When the timer expires and is restarted, it will return +roughly \f(CW7\fR (likely slightly less as callback invocation takes some time, +too), and so on. .IP "ev_tstamp repeat [read\-write]" 4 .IX Item "ev_tstamp repeat [read-write]" The current \f(CW\*(C`repeat\*(C'\fR value. Will be used each time the watcher times out @@ -1891,8 +2012,8 @@ inactivity. \& // reset the timeout to start ticking again at 10 seconds \& ev_timer_again (&mytimer); .Ve -.ie n .Sh """ev_periodic"" \- to cron or not to cron?" -.el .Sh "\f(CWev_periodic\fP \- to cron or not to cron?" +.ie n .SS """ev_periodic"" \- to cron or not to cron?" +.el .SS "\f(CWev_periodic\fP \- to cron or not to cron?" .IX Subsection "ev_periodic - to cron or not to cron?" Periodic watchers are also timers of a kind, but they are very versatile (and unfortunately a bit complex). @@ -2090,8 +2211,8 @@ Example: Call a callback every hour, starting now: \& fmod (ev_now (loop), 3600.), 3600., 0); \& ev_periodic_start (loop, &hourly_tick); .Ve -.ie n .Sh """ev_signal"" \- signal me when a signal gets signalled!" -.el .Sh "\f(CWev_signal\fP \- signal me when a signal gets signalled!" +.ie n .SS """ev_signal"" \- signal me when a signal gets signalled!" +.el .SS "\f(CWev_signal\fP \- signal me when a signal gets signalled!" .IX Subsection "ev_signal - signal me when a signal gets signalled!" Signal watchers will trigger an event when the process receives a specific signal one or more times. Even though signals are very asynchronous, libev @@ -2145,8 +2266,8 @@ Example: Try to exit cleanly on \s-1SIGINT\s0. \& ev_signal_init (&signal_watcher, sigint_cb, SIGINT); \& ev_signal_start (loop, &signal_watcher); .Ve -.ie n .Sh """ev_child"" \- watch out for process status changes" -.el .Sh "\f(CWev_child\fP \- watch out for process status changes" +.ie n .SS """ev_child"" \- watch out for process status changes" +.el .SS "\f(CWev_child\fP \- watch out for process status changes" .IX Subsection "ev_child - watch out for process status changes" Child watchers trigger when your process receives a \s-1SIGCHLD\s0 in response to some child status changes (most typically when a child of yours dies or @@ -2154,12 +2275,16 @@ exits). It is permissible to install a child watcher \fIafter\fR the child has been forked (which implies it might have already exited), as long as the event loop isn't entered (or is continued from a watcher), i.e., forking and then immediately registering a watcher for the child is fine, -but forking and registering a watcher a few event loop iterations later is -not. +but forking and registering a watcher a few event loop iterations later or +in the next callback invocation is not. .PP Only the default event loop is capable of handling signals, and therefore you can only register child watchers in the default event loop. .PP +Due to some design glitches inside libev, child watchers will always be +handled at maximum priority (their priority is set to \f(CW\*(C`EV_MAXPRI\*(C'\fR by +libev) +.PP \fIProcess Interaction\fR .IX Subsection "Process Interaction" .PP @@ -2247,8 +2372,8 @@ its completion. \& ev_child_start (EV_DEFAULT_ &cw); \& } .Ve -.ie n .Sh """ev_stat"" \- did the file attributes just change?" -.el .Sh "\f(CWev_stat\fP \- did the file attributes just change?" +.ie n .SS """ev_stat"" \- did the file attributes just change?" +.el .SS "\f(CWev_stat\fP \- did the file attributes just change?" .IX Subsection "ev_stat - did the file attributes just change?" This watches a file system path for attribute changes. That is, it calls \&\f(CW\*(C`stat\*(C'\fR on that path in regular intervals (or when the \s-1OS\s0 says it changed) @@ -2472,8 +2597,8 @@ one might do the work both on \f(CW\*(C`ev_stat\*(C'\fR callback invocation \fIa \& ev_stat_start (loop, &passwd); \& ev_timer_init (&timer, timer_cb, 0., 1.02); .Ve -.ie n .Sh """ev_idle"" \- when you've got nothing better to do..." -.el .Sh "\f(CWev_idle\fP \- when you've got nothing better to do..." +.ie n .SS """ev_idle"" \- when you've got nothing better to do..." +.el .SS "\f(CWev_idle\fP \- when you've got nothing better to do..." .IX Subsection "ev_idle - when you've got nothing better to do..." Idle watchers trigger events when no other events of the same or higher priority are pending (prepare, check and other idle watchers do not count @@ -2519,10 +2644,10 @@ callback, free it. Also, use no error checking, as usual. \& \& ev_idle *idle_watcher = malloc (sizeof (ev_idle)); \& ev_idle_init (idle_watcher, idle_cb); -\& ev_idle_start (loop, idle_cb); +\& ev_idle_start (loop, idle_watcher); .Ve -.ie n .Sh """ev_prepare""\fP and \f(CW""ev_check"" \- customise your event loop!" -.el .Sh "\f(CWev_prepare\fP and \f(CWev_check\fP \- customise your event loop!" +.ie n .SS """ev_prepare"" and ""ev_check"" \- customise your event loop!" +.el .SS "\f(CWev_prepare\fP and \f(CWev_check\fP \- customise your event loop!" .IX Subsection "ev_prepare and ev_check - customise your event loop!" Prepare and check watchers are usually (but not always) used in pairs: prepare watchers get invoked before the process blocks and check watchers @@ -2622,7 +2747,7 @@ the callbacks for the IO/timeout watchers might not have been called yet. \& adns_beforepoll (ads, fds, &nfd, &timeout, timeval_from (ev_time ())); \& \& /* the callback is illegal, but won\*(Aqt be called as we stop during check */ -\& ev_timer_init (&tw, 0, timeout * 1e\-3); +\& ev_timer_init (&tw, 0, timeout * 1e\-3, 0.); \& ev_timer_start (loop, &tw); \& \& // create one ev_io per pollfd @@ -2723,8 +2848,8 @@ libglib event loop. \& return got_events; \& } .Ve -.ie n .Sh """ev_embed"" \- when one backend isn't enough..." -.el .Sh "\f(CWev_embed\fP \- when one backend isn't enough..." +.ie n .SS """ev_embed"" \- when one backend isn't enough..." +.el .SS "\f(CWev_embed\fP \- when one backend isn't enough..." .IX Subsection "ev_embed - when one backend isn't enough..." This is a rather advanced watcher type that lets you embed one event loop into another (currently only \f(CW\*(C`ev_io\*(C'\fR events are supported in the embedded @@ -2856,8 +2981,8 @@ kqueue implementation). Store the kqueue/socket\-only event loop in \& \& // now use loop_socket for all sockets, and loop for everything else .Ve -.ie n .Sh """ev_fork"" \- the audacity to resume the event loop after a fork" -.el .Sh "\f(CWev_fork\fP \- the audacity to resume the event loop after a fork" +.ie n .SS """ev_fork"" \- the audacity to resume the event loop after a fork" +.el .SS "\f(CWev_fork\fP \- the audacity to resume the event loop after a fork" .IX Subsection "ev_fork - the audacity to resume the event loop after a fork" Fork watchers are called when a \f(CW\*(C`fork ()\*(C'\fR was detected (usually because whoever is a good citizen cared to tell libev about it by calling @@ -2908,8 +3033,8 @@ also that in that case, you have to re-register any signal watchers. Initialises and configures the fork watcher \- it has no parameters of any kind. There is a \f(CW\*(C`ev_fork_set\*(C'\fR macro, but using it is utterly pointless, believe me. -.ie n .Sh """ev_async"" \- how to wake up another event loop" -.el .Sh "\f(CWev_async\fP \- how to wake up another event loop" +.ie n .SS """ev_async"" \- how to wake up another event loop" +.el .SS "\f(CWev_async\fP \- how to wake up another event loop" .IX Subsection "ev_async - how to wake up another event loop" 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 @@ -3157,16 +3282,16 @@ types of functors please contact the author (preferably after implementing it). .PP Here is a list of things available in the \f(CW\*(C`ev\*(C'\fR namespace: -.ie n .IP """ev::READ""\fR, \f(CW""ev::WRITE"" etc." 4 +.ie n .IP """ev::READ"", ""ev::WRITE"" etc." 4 .el .IP "\f(CWev::READ\fR, \f(CWev::WRITE\fR etc." 4 .IX Item "ev::READ, ev::WRITE etc." These are just enum values with the same values as the \f(CW\*(C`EV_READ\*(C'\fR etc. macros from \fIev.h\fR. -.ie n .IP """ev::tstamp""\fR, \f(CW""ev::now""" 4 +.ie n .IP """ev::tstamp"", ""ev::now""" 4 .el .IP "\f(CWev::tstamp\fR, \f(CWev::now\fR" 4 .IX Item "ev::tstamp, ev::now" Aliases to the same types/functions as with the \f(CW\*(C`ev_\*(C'\fR prefix. -.ie n .IP """ev::io""\fR, \f(CW""ev::timer""\fR, \f(CW""ev::periodic""\fR, \f(CW""ev::idle""\fR, \f(CW""ev::sig"" etc." 4 +.ie n .IP """ev::io"", ""ev::timer"", ""ev::periodic"", ""ev::idle"", ""ev::sig"" etc." 4 .el .IP "\f(CWev::io\fR, \f(CWev::timer\fR, \f(CWev::periodic\fR, \f(CWev::idle\fR, \f(CWev::sig\fR etc." 4 .IX Item "ev::io, ev::timer, ev::periodic, ev::idle, ev::sig etc." For each \f(CW\*(C`ev_TYPE\*(C'\fR watcher in \fIev.h\fR there is a corresponding class of @@ -3286,7 +3411,7 @@ constructor already stores the event loop. .IP "w\->stop ()" 4 .IX Item "w->stop ()" Stops the watcher if it is active. Again, no \f(CW\*(C`loop\*(C'\fR argument. -.ie n .IP "w\->again () (""ev::timer""\fR, \f(CW""ev::periodic"" only)" 4 +.ie n .IP "w\->again () (""ev::timer"", ""ev::periodic"" only)" 4 .el .IP "w\->again () (\f(CWev::timer\fR, \f(CWev::periodic\fR only)" 4 .IX Item "w->again () (ev::timer, ev::periodic only)" For \f(CW\*(C`ev::timer\*(C'\fR and \f(CW\*(C`ev::periodic\*(C'\fR, this invokes the corresponding @@ -3371,7 +3496,7 @@ functions and callbacks have an initial \f(CW\*(C`struct ev_loop *\*(C'\fR argum .PP To make it easier to write programs that cope with either variant, the following macros are defined: -.ie n .IP """EV_A""\fR, \f(CW""EV_A_""" 4 +.ie n .IP """EV_A"", ""EV_A_""" 4 .el .IP "\f(CWEV_A\fR, \f(CWEV_A_\fR" 4 .IX Item "EV_A, EV_A_" This provides the loop \fIargument\fR for functions, if one is required (\*(L"ev @@ -3386,7 +3511,7 @@ loop argument\*(R"). The \f(CW\*(C`EV_A\*(C'\fR form is used when this is the so .Sp It assumes the variable \f(CW\*(C`loop\*(C'\fR of type \f(CW\*(C`struct ev_loop *\*(C'\fR is in scope, which is often provided by the following macro. -.ie n .IP """EV_P""\fR, \f(CW""EV_P_""" 4 +.ie n .IP """EV_P"", ""EV_P_""" 4 .el .IP "\f(CWEV_P\fR, \f(CWEV_P_\fR" 4 .IX Item "EV_P, EV_P_" This provides the loop \fIparameter\fR for functions, if one is required (\*(L"ev @@ -3403,12 +3528,12 @@ loop parameter\*(R"). The \f(CW\*(C`EV_P\*(C'\fR form is used when this is the s .Sp It declares a parameter \f(CW\*(C`loop\*(C'\fR of type \f(CW\*(C`struct ev_loop *\*(C'\fR, quite suitable for use with \f(CW\*(C`EV_A\*(C'\fR. -.ie n .IP """EV_DEFAULT""\fR, \f(CW""EV_DEFAULT_""" 4 +.ie n .IP """EV_DEFAULT"", ""EV_DEFAULT_""" 4 .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"). -.ie n .IP """EV_DEFAULT_UC""\fR, \f(CW""EV_DEFAULT_UC_""" 4 +.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_" Usage identical to \f(CW\*(C`EV_DEFAULT\*(C'\fR and \f(CW\*(C`EV_DEFAULT_\*(C'\fR, but requires that the @@ -3446,7 +3571,7 @@ The goal is to enable you to just copy the necessary files into your source directory without having to change even a single line in them, so you can easily upgrade by simply copying (or having a checked-out copy of libev somewhere in your source tree). -.Sh "\s-1FILESETS\s0" +.SS "\s-1FILESETS\s0" .IX Subsection "FILESETS" Depending on what features you need you need to include one or more sets of files in your application. @@ -3535,7 +3660,7 @@ For this of course you need the m4 file: .Vb 1 \& libev.m4 .Ve -.Sh "\s-1PREPROCESSOR\s0 \s-1SYMBOLS/MACROS\s0" +.SS "\s-1PREPROCESSOR\s0 \s-1SYMBOLS/MACROS\s0" .IX Subsection "PREPROCESSOR SYMBOLS/MACROS" Libev can be configured via a variety of preprocessor symbols you have to define before including any of its files. The default in the absence of @@ -3744,9 +3869,19 @@ defined to be \f(CW0\fR, then they are not. .IP "\s-1EV_MINIMAL\s0" 4 .IX Item "EV_MINIMAL" If you need to shave off some kilobytes of code at the expense of some -speed, define this symbol to \f(CW1\fR. Currently this is used to override some -inlining decisions, saves roughly 30% code size on amd64. It also selects a -much smaller 2\-heap for timer management over the default 4\-heap. +speed (but with the full \s-1API\s0), define this symbol to \f(CW1\fR. Currently this +is used to override some inlining decisions, saves roughly 30% code size +on amd64. It also selects a much smaller 2\-heap for timer management over +the default 4\-heap. +.Sp +You can save even more by disabling watcher types you do not need +and setting \f(CW\*(C`EV_MAXPRI\*(C'\fR == \f(CW\*(C`EV_MINPRI\*(C'\fR. Also, disabling \f(CW\*(C`assert\*(C'\fR +(\f(CW\*(C`\-DNDEBUG\*(C'\fR) will usually reduce code size a lot. +.Sp +Defining \f(CW\*(C`EV_MINIMAL\*(C'\fR to \f(CW2\fR will additionally reduce the core \s-1API\s0 to +provide a bare-bones event library. See \f(CW\*(C`ev.h\*(C'\fR for details on what parts +of the \s-1API\s0 are still available, and do not complain if this subset changes +over time. .IP "\s-1EV_PID_HASHSIZE\s0" 4 .IX Item "EV_PID_HASHSIZE" \&\f(CW\*(C`ev_child\*(C'\fR watchers use a small hash table to distribute workload by @@ -3820,7 +3955,7 @@ definition and a statement, respectively. See the \fIev.h\fR header file for their default definitions. One possible use for overriding these is to avoid the \f(CW\*(C`struct ev_loop *\*(C'\fR as first argument in all cases, or to use method calls instead of plain function calls in \*(C+. -.Sh "\s-1EXPORTED\s0 \s-1API\s0 \s-1SYMBOLS\s0" +.SS "\s-1EXPORTED\s0 \s-1API\s0 \s-1SYMBOLS\s0" .IX Subsection "EXPORTED API SYMBOLS" If you need to re-export the \s-1API\s0 (e.g. via a \s-1DLL\s0) and you need a list of exported symbols, you can use the provided \fISymbol.*\fR files which list @@ -3850,7 +3985,7 @@ This would create a file \fIwrap.h\fR which essentially looks like this: \& #define ev_check_stop myprefix_ev_check_stop \& ... .Ve -.Sh "\s-1EXAMPLES\s0" +.SS "\s-1EXAMPLES\s0" .IX Subsection "EXAMPLES" For a real-world example of a program the includes libev verbatim, you can have a look at the \s-1EV\s0 perl module @@ -3885,7 +4020,7 @@ And a \fIev_cpp.C\fR implementation file that contains libev proper and is compi .Ve .SH "INTERACTION WITH OTHER PROGRAMS OR LIBRARIES" .IX Header "INTERACTION WITH OTHER PROGRAMS OR LIBRARIES" -.Sh "\s-1THREADS\s0 \s-1AND\s0 \s-1COROUTINES\s0" +.SS "\s-1THREADS\s0 \s-1AND\s0 \s-1COROUTINES\s0" .IX Subsection "THREADS AND COROUTINES" \fI\s-1THREADS\s0\fR .IX Subsection "THREADS" @@ -3941,20 +4076,173 @@ work in the default loop by registering the signal watcher with the default loop and triggering an \f(CW\*(C`ev_async\*(C'\fR watcher from the default loop watcher callback into the event loop interested in the signal. .PP +\s-1THREAD\s0 \s-1LOCKING\s0 \s-1EXAMPLE\s0 +.IX Subsection "THREAD LOCKING EXAMPLE" +.PP +Here is a fictitious example of how to run an event loop in a different +thread than where callbacks are being invoked and watchers are +created/added/removed. +.PP +For a real-world example, see the \f(CW\*(C`EV::Loop::Async\*(C'\fR perl module, +which uses exactly this technique (which is suited for many high-level +languages). +.PP +The example uses a pthread mutex to protect the loop data, a condition +variable to wait for callback invocations, an async watcher to notify the +event loop thread and an unspecified mechanism to wake up the main thread. +.PP +First, you need to associate some data with the event loop: +.PP +.Vb 6 +\& typedef struct { +\& mutex_t lock; /* global loop lock */ +\& ev_async async_w; +\& thread_t tid; +\& cond_t invoke_cv; +\& } userdata; +\& +\& void prepare_loop (EV_P) +\& { +\& // for simplicity, we use a static userdata struct. +\& static userdata u; +\& +\& ev_async_init (&u\->async_w, async_cb); +\& ev_async_start (EV_A_ &u\->async_w); +\& +\& pthread_mutex_init (&u\->lock, 0); +\& pthread_cond_init (&u\->invoke_cv, 0); +\& +\& // now associate this with the loop +\& ev_set_userdata (EV_A_ u); +\& 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 +\& pthread_create (&u\->tid, 0, l_run, EV_A); +\& } +.Ve +.PP +The callback for the \f(CW\*(C`ev_async\*(C'\fR watcher does nothing: the watcher is used +solely to wake up the event loop so it takes notice of any new watchers +that might have been added: +.PP +.Vb 5 +\& static void +\& async_cb (EV_P_ ev_async *w, int revents) +\& { +\& // just used for the side effects +\& } +.Ve +.PP +The \f(CW\*(C`l_release\*(C'\fR and \f(CW\*(C`l_acquire\*(C'\fR callbacks simply unlock/lock the mutex +protecting the loop data, respectively. +.PP +.Vb 6 +\& static void +\& l_release (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& pthread_mutex_unlock (&u\->lock); +\& } +\& +\& static void +\& l_acquire (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& pthread_mutex_lock (&u\->lock); +\& } +.Ve +.PP +The event loop thread first acquires the mutex, and then jumps straight +into \f(CW\*(C`ev_loop\*(C'\fR: +.PP +.Vb 4 +\& void * +\& l_run (void *thr_arg) +\& { +\& struct ev_loop *loop = (struct ev_loop *)thr_arg; +\& +\& l_acquire (EV_A); +\& pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); +\& ev_loop (EV_A_ 0); +\& l_release (EV_A); +\& +\& return 0; +\& } +.Ve +.PP +Instead of invoking all pending watchers, the \f(CW\*(C`l_invoke\*(C'\fR callback will +signal the main thread via some unspecified mechanism (signals? pipe +writes? \f(CW\*(C`Async::Interrupt\*(C'\fR?) and then waits until all pending watchers +have been called (in a while loop because a) spurious wakeups are possible +and b) skipping inter-thread-communication when there are no pending +watchers is very beneficial): +.PP +.Vb 4 +\& static void +\& l_invoke (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& +\& while (ev_pending_count (EV_A)) +\& { +\& wake_up_other_thread_in_some_magic_or_not_so_magic_way (); +\& pthread_cond_wait (&u\->invoke_cv, &u\->lock); +\& } +\& } +.Ve +.PP +Now, whenever the main thread gets told to invoke pending watchers, it +will grab the lock, call \f(CW\*(C`ev_invoke_pending\*(C'\fR and then signal the loop +thread to continue: +.PP +.Vb 4 +\& static void +\& real_invoke_pending (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& +\& pthread_mutex_lock (&u\->lock); +\& ev_invoke_pending (EV_A); +\& pthread_cond_signal (&u\->invoke_cv); +\& pthread_mutex_unlock (&u\->lock); +\& } +.Ve +.PP +Whenever you want to start/stop a watcher or do other modifications to an +event loop, you will now have to lock: +.PP +.Vb 2 +\& ev_timer timeout_watcher; +\& userdata *u = ev_userdata (EV_A); +\& +\& ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); +\& +\& pthread_mutex_lock (&u\->lock); +\& ev_timer_start (EV_A_ &timeout_watcher); +\& ev_async_send (EV_A_ &u\->async_w); +\& pthread_mutex_unlock (&u\->lock); +.Ve +.PP +Note that sending the \f(CW\*(C`ev_async\*(C'\fR watcher is required because otherwise +an event loop currently blocking in the kernel will have no knowledge +about the newly added timer. By waking up the loop it will pick up any new +watchers in the next event loop iteration. +.PP \fI\s-1COROUTINES\s0\fR .IX Subsection "COROUTINES" .PP Libev is very accommodating to coroutines (\*(L"cooperative threads\*(R"): libev fully supports nesting calls to its functions from different coroutines (e.g. you can call \f(CW\*(C`ev_loop\*(C'\fR on the same loop from two -different coroutines, and switch freely between both coroutines running the -loop, as long as you don't confuse yourself). The only exception is that -you must not do this from \f(CW\*(C`ev_periodic\*(C'\fR reschedule callbacks. +different coroutines, and switch freely between both coroutines running +the loop, as long as you don't confuse yourself). The only exception is +that you must not do this from \f(CW\*(C`ev_periodic\*(C'\fR reschedule callbacks. .PP Care has been taken to ensure that libev does not keep local state inside \&\f(CW\*(C`ev_loop\*(C'\fR, and other calls do not usually allow for coroutine switches as they do not call any callbacks. -.Sh "\s-1COMPILER\s0 \s-1WARNINGS\s0" +.SS "\s-1COMPILER\s0 \s-1WARNINGS\s0" .IX Subsection "COMPILER WARNINGS" Depending on your compiler and compiler settings, you might get no or a lot of warnings when compiling libev code. Some people are apparently @@ -3981,7 +4269,7 @@ While libev is written to generate as few warnings as possible, with any compiler warnings enabled unless you are prepared to cope with them (e.g. by ignoring them). Remember that warnings are just that: warnings, not errors, or proof of bugs. -.Sh "\s-1VALGRIND\s0" +.SS "\s-1VALGRIND\s0" .IX Subsection "VALGRIND" Valgrind has a special section here because it is a popular tool that is highly useful. Unfortunately, valgrind reports are very hard to interpret. @@ -4016,7 +4304,7 @@ If you need, for some reason, empty reports from valgrind for your project I suggest using suppression lists. .SH "PORTABILITY NOTES" .IX Header "PORTABILITY NOTES" -.Sh "\s-1WIN32\s0 \s-1PLATFORM\s0 \s-1LIMITATIONS\s0 \s-1AND\s0 \s-1WORKAROUNDS\s0" +.SS "\s-1WIN32\s0 \s-1PLATFORM\s0 \s-1LIMITATIONS\s0 \s-1AND\s0 \s-1WORKAROUNDS\s0" .IX Subsection "WIN32 PLATFORM LIMITATIONS AND WORKAROUNDS" Win32 doesn't support any of the standards (e.g. \s-1POSIX\s0) that libev requires, and its I/O model is fundamentally incompatible with the \s-1POSIX\s0 @@ -4113,11 +4401,11 @@ runtime libraries. This might get you to about \f(CW512\fR or \f(CW2048\fR socke (depending on windows version and/or the phase of the moon). To get more, you need to wrap all I/O functions and provide your own fd management, but the cost of calling select (O(nA\*^X)) will likely make this unworkable. -.Sh "\s-1PORTABILITY\s0 \s-1REQUIREMENTS\s0" +.SS "\s-1PORTABILITY\s0 \s-1REQUIREMENTS\s0" .IX Subsection "PORTABILITY REQUIREMENTS" In addition to a working ISO-C implementation and of course the backend-specific APIs, libev relies on a few additional extensions: -.ie n .IP """void (*)(ev_watcher_type *, int revents)""\fR must have compatible calling conventions regardless of \f(CW""ev_watcher_type *""." 4 +.ie n .IP """void (*)(ev_watcher_type *, int revents)"" must have compatible calling conventions regardless of ""ev_watcher_type *""." 4 .el .IP "\f(CWvoid (*)(ev_watcher_type *, int revents)\fR must have compatible calling conventions regardless of \f(CWev_watcher_type *\fR." 4 .IX Item "void (*)(ev_watcher_type *, int revents) must have compatible calling conventions regardless of ev_watcher_type *." Libev assumes not only that all watcher pointers have the same internal @@ -4159,7 +4447,9 @@ watchers. The type \f(CW\*(C`double\*(C'\fR 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. This requirement is fulfilled by -implementations implementing \s-1IEEE\s0 754 (basically all existing ones). +implementations implementing \s-1IEEE\s0 754, which is basically all existing +ones. With \s-1IEEE\s0 754 doubles, you get microsecond accuracy until at least +2200. .PP If you know of other additional requirements drop me a note. .SH "ALGORITHMIC COMPLEXITIES" diff --git a/deps/libev/ev.c b/deps/libev/ev.c index a1a8ce13ee..3214fba702 100644 --- a/deps/libev/ev.c +++ b/deps/libev/ev.c @@ -59,6 +59,8 @@ extern "C" { # define EV_USE_MONOTONIC 1 # endif # endif +# elif !defined(EV_USE_CLOCK_SYSCALL) +# define EV_USE_CLOCK_SYSCALL 0 # endif # if HAVE_CLOCK_GETTIME @@ -284,6 +286,20 @@ extern "C" { # define EV_HEAP_CACHE_AT !EV_MINIMAL #endif +/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ +/* which makes programs even slower. might work on other unices, too. */ +#if EV_USE_CLOCK_SYSCALL +# include +# ifdef SYS_clock_gettime +# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) +# undef EV_USE_MONOTONIC +# define EV_USE_MONOTONIC 1 +# else +# undef EV_USE_CLOCK_SYSCALL +# define EV_USE_CLOCK_SYSCALL 0 +# endif +#endif + /* this block fixes any misconfiguration where we know we run into trouble otherwise */ #ifndef CLOCK_MONOTONIC @@ -322,15 +338,6 @@ extern "C" { # include #endif -/* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */ -/* which makes programs even slower. might work on other unices, too. */ -#if EV_USE_CLOCK_SYSCALL -# include -# define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts)) -# undef EV_USE_MONOTONIC -# define EV_USE_MONOTONIC 1 -#endif - #if EV_USE_EVENTFD /* our minimum requirement is glibc 2.7 which has the stub, but not the header */ # include @@ -386,8 +393,13 @@ int eventfd (unsigned int initval, int flags); # define inline_speed static inline #endif -#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) -#define ABSPRI(w) (((W)w)->priority - EV_MINPRI) +#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) + +#if EV_MINPRI == EV_MAXPRI +# define ABSPRI(w) (((W)w), 0) +#else +# define ABSPRI(w) (((W)w)->priority - EV_MINPRI) +#endif #define EMPTY /* required for microsofts broken pseudo-c compiler */ #define EMPTY2(a,b) /* used to suppress some warnings */ @@ -480,12 +492,15 @@ ev_realloc (void *ptr, long size) /*****************************************************************************/ +/* set in reify when reification needed */ +#define EV_ANFD_REIFY 1 + /* file descriptor info structure */ typedef struct { WL head; unsigned char events; /* the events watched for */ - unsigned char reify; /* flag set when this ANFD needs reification */ + unsigned char reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) */ unsigned char emask; /* the epoll backend stores the actual kernel mask in here */ unsigned char unused; #if EV_USE_EPOLL @@ -557,8 +572,21 @@ typedef struct #endif +#if EV_MINIMAL < 2 +# define EV_RELEASE_CB if (expect_false (release_cb)) release_cb (EV_A) +# define EV_ACQUIRE_CB if (expect_false (acquire_cb)) acquire_cb (EV_A) +# define EV_INVOKE_PENDING invoke_cb (EV_A) +#else +# define EV_RELEASE_CB (void)0 +# define EV_ACQUIRE_CB (void)0 +# define EV_INVOKE_PENDING ev_invoke_pending (EV_A) +#endif + +#define EVUNLOOP_RECURSE 0x80 + /*****************************************************************************/ +#ifndef EV_HAVE_EV_TIME ev_tstamp ev_time (void) { @@ -575,6 +603,7 @@ ev_time (void) gettimeofday (&tv, 0); return tv.tv_sec + tv.tv_usec * 1e-6; } +#endif inline_size ev_tstamp get_clock (void) @@ -620,7 +649,7 @@ ev_sleep (ev_tstamp delay) tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6); /* here we rely on sys/time.h + sys/types.h + unistd.h providing select */ - /* somehting nto guaranteed by newer posix versions, but guaranteed */ + /* something not guaranteed by newer posix versions, but guaranteed */ /* by older ones */ select (0, 0, 0, 0, &tv); #endif @@ -738,7 +767,7 @@ queue_events (EV_P_ W *events, int eventcnt, int type) /*****************************************************************************/ inline_speed void -fd_event (EV_P_ int fd, int revents) +fd_event_nc (EV_P_ int fd, int revents) { ANFD *anfd = anfds + fd; ev_io *w; @@ -752,11 +781,22 @@ fd_event (EV_P_ int fd, int revents) } } +/* do not submit kernel events for fds that have reify set */ +/* because that means they changed while we were polling for new events */ +inline_speed void +fd_event (EV_P_ int fd, int revents) +{ + ANFD *anfd = anfds + fd; + + if (expect_true (!anfd->reify)) + fd_event_nc (EV_A_ fd, revents); +} + void ev_feed_fd_event (EV_P_ int fd, int revents) { if (fd >= 0 && fd < anfdmax) - fd_event (EV_A_ fd, revents); + fd_event_nc (EV_A_ fd, revents); } /* make sure the external fd watch events are in-sync */ @@ -881,7 +921,7 @@ fd_rearm_all (EV_P) { anfds [fd].events = 0; anfds [fd].emask = 0; - fd_change (EV_A_ fd, EV__IOFDSET | 1); + fd_change (EV_A_ fd, EV__IOFDSET | EV_ANFD_REIFY); } } @@ -1345,12 +1385,19 @@ ev_backend (EV_P) return backend; } +#if EV_MINIMAL < 2 unsigned int ev_loop_count (EV_P) { return loop_count; } +unsigned int +ev_loop_depth (EV_P) +{ + return loop_depth; +} + void ev_set_io_collect_interval (EV_P_ ev_tstamp interval) { @@ -1363,6 +1410,30 @@ ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) timeout_blocktime = interval; } +void +ev_set_userdata (EV_P_ void *data) +{ + userdata = data; +} + +void * +ev_userdata (EV_P) +{ + return userdata; +} + +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)) +{ + invoke_cb = invoke_pending_cb; +} + +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)) +{ + release_cb = release; + acquire_cb = acquire; +} +#endif + /* initialise a loop structure, must be zero-initialised */ static void noinline loop_init (EV_P_ unsigned int flags) @@ -1393,6 +1464,9 @@ loop_init (EV_P_ unsigned int flags) mn_now = get_clock (); now_floor = mn_now; rtmn_diff = ev_rt_now - mn_now; +#if EV_MINIMAL < 2 + invoke_cb = ev_invoke_pending; +#endif io_blocktime = 0.; timeout_blocktime = 0.; @@ -1596,6 +1670,7 @@ ev_loop_fork (EV_P) { postfork = 1; /* must be in line with ev_default_fork */ } +#endif /* multiplicity */ #if EV_VERIFY static void noinline @@ -1633,6 +1708,7 @@ array_verify (EV_P_ W *ws, int cnt) } #endif +#if EV_MINIMAL < 2 void ev_loop_verify (EV_P) { @@ -1695,8 +1771,7 @@ ev_loop_verify (EV_P) # endif #endif } - -#endif /* multiplicity */ +#endif #if EV_MULTIPLICITY struct ev_loop * @@ -1767,8 +1842,20 @@ ev_invoke (EV_P_ void *w, int revents) EV_CB_INVOKE ((W)w, revents); } -inline_speed void -call_pending (EV_P) +unsigned int +ev_pending_count (EV_P) +{ + int pri; + unsigned int count = 0; + + for (pri = NUMPRI; pri--; ) + count += pendingcnt [pri]; + + return count; +} + +void noinline +ev_invoke_pending (EV_P) { int pri; @@ -1950,11 +2037,10 @@ timers_reschedule (EV_P_ ev_tstamp adjust) inline_speed void time_update (EV_P_ ev_tstamp max_block) { - int i; - #if EV_USE_MONOTONIC if (expect_true (have_monotonic)) { + int i; ev_tstamp odiff = rtmn_diff; mn_now = get_clock (); @@ -2014,14 +2100,18 @@ time_update (EV_P_ ev_tstamp max_block) } } -static int loop_done; - void ev_loop (EV_P_ int flags) { +#if EV_MINIMAL < 2 + ++loop_depth; +#endif + + assert (("libev: ev_loop recursion during release detected", loop_done != EVUNLOOP_RECURSE)); + loop_done = EVUNLOOP_CANCEL; - call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */ + EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */ do { @@ -2044,7 +2134,7 @@ ev_loop (EV_P_ int flags) if (forkcnt) { queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK); - call_pending (EV_A); + EV_INVOKE_PENDING; } #endif @@ -2052,9 +2142,12 @@ ev_loop (EV_P_ int flags) if (expect_false (preparecnt)) { queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE); - call_pending (EV_A); + EV_INVOKE_PENDING; } + if (expect_false (loop_done)) + break; + /* we might have forked, so reify kernel state if necessary */ if (expect_false (postfork)) loop_fork (EV_A); @@ -2069,6 +2162,9 @@ ev_loop (EV_P_ int flags) if (expect_true (!(flags & EVLOOP_NONBLOCK || idleall || !activecnt))) { + /* remember old timestamp for io_blocktime calculation */ + ev_tstamp prev_mn_now = mn_now; + /* update time to cancel out callback processing overhead */ time_update (EV_A_ 1e100); @@ -2088,23 +2184,32 @@ ev_loop (EV_P_ int flags) } #endif + /* don't let timeouts decrease the waittime below timeout_blocktime */ if (expect_false (waittime < timeout_blocktime)) waittime = timeout_blocktime; - sleeptime = waittime - backend_fudge; + /* extra check because io_blocktime is commonly 0 */ + if (expect_false (io_blocktime)) + { + sleeptime = io_blocktime - (mn_now - prev_mn_now); - if (expect_true (sleeptime > io_blocktime)) - sleeptime = io_blocktime; + if (sleeptime > waittime - backend_fudge) + sleeptime = waittime - backend_fudge; - if (sleeptime) - { - ev_sleep (sleeptime); - waittime -= sleeptime; + if (expect_true (sleeptime > 0.)) + { + ev_sleep (sleeptime); + waittime -= sleeptime; + } } } +#if EV_MINIMAL < 2 ++loop_count; +#endif + assert ((loop_done = EVUNLOOP_RECURSE, 1)); /* assert for side effect */ backend_poll (EV_A_ waittime); + assert ((loop_done = EVUNLOOP_CANCEL, 1)); /* assert for side effect */ /* update ev_rt_now, do magic */ time_update (EV_A_ waittime + sleeptime); @@ -2125,7 +2230,7 @@ ev_loop (EV_P_ int flags) if (expect_false (checkcnt)) queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK); - call_pending (EV_A); + EV_INVOKE_PENDING; } while (expect_true ( activecnt @@ -2135,6 +2240,10 @@ ev_loop (EV_P_ int flags) if (loop_done == EVUNLOOP_ONE) loop_done = EVUNLOOP_CANCEL; + +#if EV_MINIMAL < 2 + --loop_depth; +#endif } void @@ -2236,10 +2345,10 @@ ev_clear_pending (EV_P_ void *w) inline_size void pri_adjust (EV_P_ W w) { - int pri = w->priority; + int pri = ev_priority (w); pri = pri < EV_MINPRI ? EV_MINPRI : pri; pri = pri > EV_MAXPRI ? EV_MAXPRI : pri; - w->priority = pri; + ev_set_priority (w, pri); } inline_speed void @@ -2276,7 +2385,7 @@ ev_io_start (EV_P_ ev_io *w) array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero); wlist_add (&anfds[fd].head, (WL)w); - fd_change (EV_A_ fd, w->events & EV__IOFDSET | 1); + fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY); w->events &= ~EV__IOFDSET; EV_FREQUENT_CHECK; @@ -2380,6 +2489,12 @@ ev_timer_again (EV_P_ ev_timer *w) EV_FREQUENT_CHECK; } +ev_tstamp +ev_timer_remaining (EV_P_ ev_timer *w) +{ + return ev_at (w) - (ev_is_active (w) ? mn_now : 0.); +} + #if EV_PERIODIC_ENABLE void noinline ev_periodic_start (EV_P_ ev_periodic *w) @@ -2490,7 +2605,7 @@ ev_signal_start (EV_P_ ev_signal *w) #if _WIN32 signal (w->signum, ev_sighandler); #else - struct sigaction sa; + struct sigaction sa = { }; sa.sa_handler = ev_sighandler; sigfillset (&sa.sa_mask); sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */ diff --git a/deps/libev/ev.h b/deps/libev/ev.h index 260544c7c2..25c3f1d806 100644 --- a/deps/libev/ev.h +++ b/deps/libev/ev.h @@ -163,7 +163,7 @@ struct ev_loop; #endif #define EV_VERSION_MAJOR 3 -#define EV_VERSION_MINOR 0 +#define EV_VERSION_MINOR 7 #ifndef EV_CB_DECLARE # define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); @@ -189,11 +189,17 @@ struct ev_loop; * or the array index + 1 in the pendings array. */ +#if EV_MINPRI == EV_MAXPRI +# define EV_DECL_PRIORITY +#else +# define EV_DECL_PRIORITY int priority; +#endif + /* shared by all watchers */ #define EV_WATCHER(type) \ int active; /* private */ \ int pending; /* private */ \ - int priority; /* private */ \ + EV_DECL_PRIORITY /* private */ \ EV_COMMON /* rw */ \ EV_CB_DECLARE (type) /* private */ @@ -461,10 +467,8 @@ ev_default_loop (unsigned int flags) struct ev_loop *ev_loop_new (unsigned int flags); void ev_loop_destroy (EV_P); void ev_loop_fork (EV_P); -void ev_loop_verify (EV_P); ev_tstamp ev_now (EV_P); /* time w.r.t. timers and the eventloop, updated after each poll */ -void ev_now_update (EV_P); #else @@ -498,6 +502,10 @@ void ev_default_destroy (void); /* destroy the default loop */ /* you can actually call it at any time, anywhere :) */ void ev_default_fork (void); +unsigned int ev_backend (EV_P); /* backend in use by loop */ + +void ev_now_update (EV_P); /* update event loop time */ + #if EV_WALK_ENABLE /* walk (almost) all watchers in the loop of a given type, invoking the */ /* callback on every such watcher. The callback might stop the watcher, */ @@ -505,8 +513,6 @@ void ev_default_fork (void); void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)); #endif -unsigned int ev_backend (EV_P); /* backend in use by loop */ -unsigned int ev_loop_count (EV_P); /* number of loop iterations */ #endif /* prototypes */ #define EVLOOP_NONBLOCK 1 /* do not block/wait */ @@ -519,36 +525,52 @@ unsigned int ev_loop_count (EV_P); /* number of loop iterations */ void ev_loop (EV_P_ int flags); void ev_unloop (EV_P_ int how); /* set to 1 to break out of event loop, set to 2 to break out of all event loops */ -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 */ - /* * ref/unref can be used to add or remove a refcount on the mainloop. every watcher - * keeps one reference. if you have a long-runing watcher you never unregister that + * keeps one reference. if you have a long-running watcher you never unregister that * should not keep ev_loop from running, unref() after starting, and ref() before stopping. */ void ev_ref (EV_P); void ev_unref (EV_P); +/* + * convenience function, wait for a single event, without registering an event watcher + * if timeout is < 0, do wait indefinitely + */ +void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); + +# if EV_MINIMAL < 2 +unsigned int ev_loop_count (EV_P); /* number of loop iterations */ +unsigned int ev_loop_depth (EV_P); /* #ev_loop enters - #ev_loop leaves */ +void ev_loop_verify (EV_P); /* abort if loop data corrupted */ + +void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ +void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ + +/* advanced stuff for threading etc. support, see docs */ +void ev_set_userdata (EV_P_ void *data); +void *ev_userdata (EV_P); +void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P)); +void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P)); + +unsigned int ev_pending_count (EV_P); /* number of pending events, if any */ +void ev_invoke_pending (EV_P); /* invoke all pending watchers */ + /* * stop/start the timer handling. */ void ev_suspend (EV_P); void ev_resume (EV_P); +#endif -/* - * 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); #endif /* these may evaluate ev multiple times, and the other arguments at most once */ /* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ #define ev_init(ev,cb_) do { \ - ((ev_watcher *)(void *)(ev))->active = \ - ((ev_watcher *)(void *)(ev))->pending = \ - ((ev_watcher *)(void *)(ev))->priority = 0; \ + ((ev_watcher *)(void *)(ev))->active = \ + ((ev_watcher *)(void *)(ev))->pending = 0; \ + ev_set_priority ((ev), 0); \ ev_set_cb ((ev), cb_); \ } while (0) @@ -581,9 +603,15 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent #define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ #define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ -#define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0) #define ev_cb(ev) (ev)->cb /* rw */ -#define ev_set_priority(ev,pri) ((ev_watcher *)(void *)(ev))->priority = (pri) + +#if EV_MINPRI == EV_MAXPRI +# define ev_priority(ev) ((ev), EV_MINPRI) +# define ev_set_priority(ev,pri) ((ev), (pri)) +#else +# define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0) +# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri) +#endif #define ev_periodic_at(ev) (((ev_watcher_time *)(ev))->at + 0.) @@ -610,6 +638,8 @@ void ev_timer_start (EV_P_ ev_timer *w); void ev_timer_stop (EV_P_ ev_timer *w); /* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ void ev_timer_again (EV_P_ ev_timer *w); +/* return remaining time */ +ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w); #if EV_PERIODIC_ENABLE void ev_periodic_start (EV_P_ ev_periodic *w); diff --git a/deps/libev/ev.pod b/deps/libev/ev.pod index 496d3f4d52..289362b7c0 100644 --- a/deps/libev/ev.pod +++ b/deps/libev/ev.pod @@ -623,6 +623,18 @@ This value can sometimes be useful as a generation counter of sorts (it "ticks" the number of loop iterations), as it roughly corresponds with C and C calls. +=item unsigned int ev_loop_depth (loop) + +Returns the number of times C was entered minus the number of +times C was exited, in other words, the recursion depth. + +Outside C, this number is zero. In a callback, this number is +C<1>, unless C was invoked recursively (or from another thread), +in which case it is higher. + +Leaving C abnormally (setjmp/longjmp, cancelling the thread +etc.), doesn't count as exit. + =item unsigned int ev_backend (loop) Returns one of the C flags indicating the event backend in @@ -813,7 +825,9 @@ By setting a higher I 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 and C) will be not affected. Setting this to a non-null value will -introduce an additional C call into most loop iterations. +introduce an additional C 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. Likewise, by setting a higher I you allow libev to spend more time collecting timeouts, at the expense of increased @@ -825,7 +839,11 @@ Many (busy) programs can usually benefit by setting the I/O collect interval to a value near C<0.1> or so, which is often enough for interactive servers (of course not for games), likewise for timeouts. It usually doesn't make much sense to set it to a lower value than C<0.01>, -as this approaches the timing granularity of most systems. +as this approaches the timing granularity of most systems. Note that if +you do transactions with the outside world and you can't increase the +parallelity, then this setting will limit your transaction rate (if you +need to poll once per transaction and the I/O collect interval is 0.01, +then you can't do more than 100 transations per second). Setting the I can improve the opportunity for saving power, as the program will "bundle" timer callback invocations that @@ -834,6 +852,77 @@ times the process sleeps and wakes up again. Another useful technique to reduce iterations/wake-ups is to use C watchers and make sure they fire on, say, one-second boundaries only. +Example: we only need 0.1s timeout granularity, and we wish not to poll +more often than 100 times per second: + + ev_set_timeout_collect_interval (EV_DEFAULT_UC_ 0.1); + ev_set_io_collect_interval (EV_DEFAULT_UC_ 0.01); + +=item ev_invoke_pending (loop) + +This call will simply invoke all pending watchers while resetting their +pending state. Normally, C does this automatically when required, +but when overriding the invoke callback this call comes handy. + +=item int ev_pending_count (loop) + +Returns the number of pending watchers - zero indicates that no watchers +are pending. + +=item ev_set_invoke_pending_cb (loop, void (*invoke_pending_cb)(EV_P)) + +This overrides the invoke pending functionality of the loop: Instead of +invoking all pending watchers when there are any, C will call +this callback instead. This is useful, for example, when you want to +invoke the actual watchers inside another context (another thread etc.). + +If you want to reset the callback, use C as new +callback. + +=item ev_set_loop_release_cb (loop, void (*release)(EV_P), void (*acquire)(EV_P)) + +Sometimes you want to share the same loop between multiple threads. This +can be done relatively simply by putting mutex_lock/unlock calls around +each call to a libev function. + +However, C 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 loop via +C and C, another way is to set these I +and I callbacks on the loop. + +When set, then C will be called just before the thread is +suspended waiting for new events, and C is called just +afterwards. + +Ideally, C will just call your mutex_unlock function, and +C will just call the mutex_lock function again. + +While event loop modifications are allowed between invocations of +C and C (that's their only purpose after all), no +modifications done will affect the event loop, i.e. adding watchers will +have no effect on the set of file descriptors being watched, or the time +waited. USe an C watcher to wake up C when you want it +to take note of any changes you made. + +In theory, threads executing C will be async-cancel safe between +invocations of C and C. + +See also the locking example in the C section later in this +document. + +=item ev_set_userdata (loop, void *data) + +=item ev_userdata (loop) + +Set and retrieve a single C associated with a loop. When +C has never been called, then C returns +C<0.> + +These two functions can be used to associate arbitrary data with a loop, +and are intended solely for the C, C and +C callbacks described above, but of course can be (ab-)used for +any other purpose as well. + =item ev_loop_verify (loop) This function only does something when C support has been @@ -1186,14 +1275,14 @@ programmers): static void t1_cb (EV_P_ ev_timer *w, int revents) { - struct my_biggy big = (struct my_biggy * + struct my_biggy big = (struct my_biggy *) (((char *)w) - offsetof (struct my_biggy, t1)); } static void t2_cb (EV_P_ ev_timer *w, int revents) { - struct my_biggy big = (struct my_biggy * + struct my_biggy big = (struct my_biggy *) (((char *)w) - offsetof (struct my_biggy, t2)); } @@ -1279,7 +1368,7 @@ other events are pending: } static void - idle-cb (EV_P_ ev_idle *w, int revents) + idle_cb (EV_P_ ev_idle *w, int revents) { // actual processing read (STDIN_FILENO, ...); @@ -1470,8 +1559,8 @@ The callback is guaranteed to be invoked only I its timeout has passed (not I, 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 with later time-out values (but this is no longer true when a -callback calls C recursively). +before ones of the same priority with later time-out values (but this is +no longer true when a callback calls C recursively). =head3 Be smart about timeouts @@ -1525,7 +1614,7 @@ member and C. At start: - ev_timer_init (timer, callback); + ev_init (timer, callback); timer->repeat = 60.; ev_timer_again (loop, timer); @@ -1597,7 +1686,7 @@ To start the timer, simply initialise the watcher and set C to the current time (meaning we just have some activity :), then call the callback, which will "do the right thing" and start the timer: - ev_timer_init (timer, callback); + ev_init (timer, callback); last_activity = ev_now (loop); callback (loop, timer, EV_TIMEOUT); @@ -1668,6 +1757,36 @@ If the event loop is suspended for a long time, you can also force an update of the time returned by C by calling C. +=head3 The special problems of suspended animation + +When you leave the server world it is quite customary to hit machines that +can suspend/hibernate - what happens to the clocks during such a suspend? + +Some quick tests made with a Linux 2.6.28 indicate that a suspend freezes +all processes, while the clocks (C, C) continue +to run until the system is suspended, but they will not advance while the +system is suspended. That means, on resume, it will be as if the program +was frozen for a few seconds, but the suspend time will not be counted +towards C when a monotonic clock source is used. The real time +clock advanced as expected, but if it is used as sole clocksource, then a +long suspend would be detected as a time jump by libev, and timers would +be adjusted accordingly. + +I would not be surprised to see different behaviour in different between +operating systems, OS versions or even different hardware. + +The other form of suspend (job control, or sending a SIGSTOP) will see a +time jump in the monotonic clocks and the realtime clock. If the program +is suspended for a very long time, and monotonic clock sources are in use, +then you can expect Cs to expire as the full suspension time +will be counted towards the timers. When no monotonic clock source is in +use, then libev will again assume a timejump and adjust accordingly. + +It might be beneficial for this latter case to call C +and C in code that handles C, to at least get +deterministic behaviour in this case (you can do nothing against +C). + =head3 Watcher-Specific Functions and Data Members =over 4 @@ -1703,6 +1822,18 @@ C value), or reset the running timer to the C value. This sounds a bit complicated, see L, above, for a usage example. +=item ev_timer_remaining (loop, ev_timer *) + +Returns the remaining time until a timer fires. If the timer is active, +then this time is relative to the current event loop time, otherwise it's +the timeout value currently configured. + +That is, after an C, C returns +C<5>. When the timer is started and one second passes, C +will return C<4>. When the timer expires and is restarted, it will return +roughly C<7> (likely slightly less as callback invocation takes some time, +too), and so on. + =item ev_tstamp repeat [read-write] The current C value. Will be used each time the watcher times out @@ -2004,12 +2135,16 @@ exits). It is permissible to install a child watcher I the child has been forked (which implies it might have already exited), as long as the event loop isn't entered (or is continued from a watcher), i.e., forking and then immediately registering a watcher for the child is fine, -but forking and registering a watcher a few event loop iterations later is -not. +but forking and registering a watcher a few event loop iterations later or +in the next callback invocation is not. Only the default event loop is capable of handling signals, and therefore you can only register child watchers in the default event loop. +Due to some design glitches inside libev, child watchers will always be +handled at maximum priority (their priority is set to C by +libev) + =head3 Process Interaction Libev grabs C as soon as the default event loop is @@ -2370,7 +2505,7 @@ callback, free it. Also, use no error checking, as usual. ev_idle *idle_watcher = malloc (sizeof (ev_idle)); ev_idle_init (idle_watcher, idle_cb); - ev_idle_start (loop, idle_cb); + ev_idle_start (loop, idle_watcher); =head2 C and C - customise your event loop! @@ -2473,7 +2608,7 @@ the callbacks for the IO/timeout watchers might not have been called yet. adns_beforepoll (ads, fds, &nfd, &timeout, timeval_from (ev_time ())); /* the callback is illegal, but won't be called as we stop during check */ - ev_timer_init (&tw, 0, timeout * 1e-3); + ev_timer_init (&tw, 0, timeout * 1e-3, 0.); ev_timer_start (loop, &tw); // create one ev_io per pollfd @@ -3645,9 +3780,19 @@ defined to be C<0>, then they are not. =item EV_MINIMAL If you need to shave off some kilobytes of code at the expense of some -speed, define this symbol to C<1>. Currently this is used to override some -inlining decisions, saves roughly 30% code size on amd64. It also selects a -much smaller 2-heap for timer management over the default 4-heap. +speed (but with the full API), define this symbol to C<1>. Currently this +is used to override some inlining decisions, saves roughly 30% code size +on amd64. It also selects a much smaller 2-heap for timer management over +the default 4-heap. + +You can save even more by disabling watcher types you do not need +and setting C == C. Also, disabling C +(C<-DNDEBUG>) will usually reduce code size a lot. + +Defining C to C<2> will additionally reduce the core API to +provide a bare-bones event library. See C for details on what parts +of the API are still available, and do not complain if this subset changes +over time. =item EV_PID_HASHSIZE @@ -3843,14 +3988,152 @@ watcher callback into the event loop interested in the signal. =back +=head4 THREAD LOCKING EXAMPLE + +Here is a fictitious example of how to run an event loop in a different +thread than where callbacks are being invoked and watchers are +created/added/removed. + +For a real-world example, see the C perl module, +which uses exactly this technique (which is suited for many high-level +languages). + +The example uses a pthread mutex to protect the loop data, a condition +variable to wait for callback invocations, an async watcher to notify the +event loop thread and an unspecified mechanism to wake up the main thread. + +First, you need to associate some data with the event loop: + + typedef struct { + mutex_t lock; /* global loop lock */ + ev_async async_w; + thread_t tid; + cond_t invoke_cv; + } userdata; + + void prepare_loop (EV_P) + { + // for simplicity, we use a static userdata struct. + static userdata u; + + ev_async_init (&u->async_w, async_cb); + ev_async_start (EV_A_ &u->async_w); + + pthread_mutex_init (&u->lock, 0); + pthread_cond_init (&u->invoke_cv, 0); + + // now associate this with the loop + ev_set_userdata (EV_A_ u); + 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 + pthread_create (&u->tid, 0, l_run, EV_A); + } + +The callback for the C watcher does nothing: the watcher is used +solely to wake up the event loop so it takes notice of any new watchers +that might have been added: + + static void + async_cb (EV_P_ ev_async *w, int revents) + { + // just used for the side effects + } + +The C and C callbacks simply unlock/lock the mutex +protecting the loop data, respectively. + + static void + l_release (EV_P) + { + userdata *u = ev_userdata (EV_A); + pthread_mutex_unlock (&u->lock); + } + + static void + l_acquire (EV_P) + { + userdata *u = ev_userdata (EV_A); + pthread_mutex_lock (&u->lock); + } + +The event loop thread first acquires the mutex, and then jumps straight +into C: + + void * + l_run (void *thr_arg) + { + struct ev_loop *loop = (struct ev_loop *)thr_arg; + + l_acquire (EV_A); + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); + ev_loop (EV_A_ 0); + l_release (EV_A); + + return 0; + } + +Instead of invoking all pending watchers, the C callback will +signal the main thread via some unspecified mechanism (signals? pipe +writes? C?) and then waits until all pending watchers +have been called (in a while loop because a) spurious wakeups are possible +and b) skipping inter-thread-communication when there are no pending +watchers is very beneficial): + + static void + l_invoke (EV_P) + { + userdata *u = ev_userdata (EV_A); + + while (ev_pending_count (EV_A)) + { + wake_up_other_thread_in_some_magic_or_not_so_magic_way (); + pthread_cond_wait (&u->invoke_cv, &u->lock); + } + } + +Now, whenever the main thread gets told to invoke pending watchers, it +will grab the lock, call C and then signal the loop +thread to continue: + + static void + real_invoke_pending (EV_P) + { + userdata *u = ev_userdata (EV_A); + + pthread_mutex_lock (&u->lock); + ev_invoke_pending (EV_A); + pthread_cond_signal (&u->invoke_cv); + pthread_mutex_unlock (&u->lock); + } + +Whenever you want to start/stop a watcher or do other modifications to an +event loop, you will now have to lock: + + ev_timer timeout_watcher; + userdata *u = ev_userdata (EV_A); + + ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); + + pthread_mutex_lock (&u->lock); + ev_timer_start (EV_A_ &timeout_watcher); + ev_async_send (EV_A_ &u->async_w); + pthread_mutex_unlock (&u->lock); + +Note that sending the C watcher is required because otherwise +an event loop currently blocking in the kernel will have no knowledge +about the newly added timer. By waking up the loop it will pick up any new +watchers in the next event loop iteration. + =head3 COROUTINES Libev is very accommodating to coroutines ("cooperative threads"): libev fully supports nesting calls to its functions from different coroutines (e.g. you can call C on the same loop from two -different coroutines, and switch freely between both coroutines running the -loop, as long as you don't confuse yourself). The only exception is that -you must not do this from C reschedule callbacks. +different coroutines, and switch freely between both coroutines running +the loop, as long as you don't confuse yourself). The only exception is +that you must not do this from C reschedule callbacks. Care has been taken to ensure that libev does not keep local state inside C, and other calls do not usually allow for coroutine switches as @@ -4067,7 +4350,9 @@ watchers. The type C 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. This requirement is fulfilled by -implementations implementing IEEE 754 (basically all existing ones). +implementations implementing IEEE 754, which is basically all existing +ones. With IEEE 754 doubles, you get microsecond accuracy until at least +2200. =back diff --git a/deps/libev/ev_epoll.c b/deps/libev/ev_epoll.c index b302e26aba..40c320ac7e 100644 --- a/deps/libev/ev_epoll.c +++ b/deps/libev/ev_epoll.c @@ -119,7 +119,11 @@ static void epoll_poll (EV_P_ ev_tstamp timeout) { int i; - int eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); + int eventcnt; + + EV_RELEASE_CB; + eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); + EV_ACQUIRE_CB; if (expect_false (eventcnt < 0)) { diff --git a/deps/libev/ev_kqueue.c b/deps/libev/ev_kqueue.c index 63828d6fea..c5f4eb76f0 100644 --- a/deps/libev/ev_kqueue.c +++ b/deps/libev/ev_kqueue.c @@ -93,9 +93,11 @@ kqueue_poll (EV_P_ ev_tstamp timeout) kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); } + EV_RELEASE_CB; ts.tv_sec = (time_t)timeout; ts.tv_nsec = (long)((timeout - (ev_tstamp)ts.tv_sec) * 1e9); res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts); + EV_ACQUIRE_CB; kqueue_changecnt = 0; if (expect_false (res < 0)) diff --git a/deps/libev/ev_poll.c b/deps/libev/ev_poll.c index 5b82b29916..c33ea02e70 100644 --- a/deps/libev/ev_poll.c +++ b/deps/libev/ev_poll.c @@ -89,7 +89,11 @@ static void poll_poll (EV_P_ ev_tstamp timeout) { struct pollfd *p; - int res = poll (polls, pollcnt, (int)ceil (timeout * 1000.)); + int res; + + EV_RELEASE_CB; + res = poll (polls, pollcnt, (int)ceil (timeout * 1000.)); + EV_ACQUIRE_CB; if (expect_false (res < 0)) { diff --git a/deps/libev/ev_port.c b/deps/libev/ev_port.c index c2dde65fb7..16fe86e757 100644 --- a/deps/libev/ev_port.c +++ b/deps/libev/ev_port.c @@ -85,9 +85,11 @@ port_poll (EV_P_ ev_tstamp timeout) struct timespec ts; uint_t nget = 1; + EV_RELEASE_CB; ts.tv_sec = (time_t)timeout; ts.tv_nsec = (long)(timeout - (ev_tstamp)ts.tv_sec) * 1e9; res = port_getn (backend_fd, port_events, port_eventmax, &nget, &ts); + EV_ACQUIRE_CB; if (res == -1) { diff --git a/deps/libev/ev_select.c b/deps/libev/ev_select.c index 173c28695e..e57c1e22bf 100644 --- a/deps/libev/ev_select.c +++ b/deps/libev/ev_select.c @@ -140,6 +140,7 @@ select_poll (EV_P_ ev_tstamp timeout) int res; int fd_setsize; + EV_RELEASE_CB; tv.tv_sec = (long)timeout; tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6); @@ -166,6 +167,7 @@ select_poll (EV_P_ ev_tstamp timeout) #else res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); #endif + EV_ACQUIRE_CB; if (expect_false (res < 0)) { diff --git a/deps/libev/ev_vars.h b/deps/libev/ev_vars.h index b91e430992..da73ca2328 100644 --- a/deps/libev/ev_vars.h +++ b/deps/libev/ev_vars.h @@ -1,7 +1,7 @@ /* * loop member variable declarations * - * Copyright (c) 2007,2008 Marc Alexander Lehmann + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -48,7 +48,7 @@ VARx(ev_tstamp, timeout_blocktime) VARx(int, backend) VARx(int, activecnt) /* total number of active events ("refcount") */ -VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ +VARx(unsigned char, loop_done) /* signal by ev_unloop */ VARx(int, backend_fd) VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */ @@ -166,5 +166,15 @@ VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) #endif +#if EV_MINIMAL < 2 || EV_GENWRAP +VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ +VARx(unsigned int, loop_depth) /* #ev_loop enters - #ev_loop leaves */ + +VARx(void *, userdata) +VAR (release_cb, void (*release_cb)(EV_P)) +VAR (acquire_cb, void (*acquire_cb)(EV_P)) +VAR (invoke_cb , void (*invoke_cb) (EV_P)) +#endif + #undef VARx diff --git a/deps/libev/ev_win32.c b/deps/libev/ev_win32.c index 61bff50b1f..a048c0be4a 100644 --- a/deps/libev/ev_win32.c +++ b/deps/libev/ev_win32.c @@ -133,22 +133,21 @@ fail: #undef pipe #define pipe(filedes) ev_pipe (filedes) - -static int -ev_gettimeofday (struct timeval *tv, struct timezone *tz) + +#define EV_HAVE_EV_TIME 1 +ev_tstamp +ev_time (void) { - struct _timeb tb; - - _ftime (&tb); + FILETIME ft; + ULARGE_INTEGER ui; - tv->tv_sec = (long)tb.time; - tv->tv_usec = ((long)tb.millitm) * 1000; + GetSystemTimeAsFileTime (&ft); + ui.u.LowPart = ft.dwLowDateTime; + ui.u.HighPart = ft.dwHighDateTime; - return 0; + /* msvc cannot convert ulonglong to double... yes, it is that sucky */ + return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7; } -#undef gettimeofday -#define gettimeofday(tv,tz) ev_gettimeofday (tv, tz) - #endif diff --git a/deps/libev/ev_wrap.h b/deps/libev/ev_wrap.h index e2c5be603f..ba99da63ae 100644 --- a/deps/libev/ev_wrap.h +++ b/deps/libev/ev_wrap.h @@ -8,7 +8,7 @@ #define timeout_blocktime ((loop)->timeout_blocktime) #define backend ((loop)->backend) #define activecnt ((loop)->activecnt) -#define loop_count ((loop)->loop_count) +#define loop_done ((loop)->loop_done) #define backend_fd ((loop)->backend_fd) #define backend_fudge ((loop)->backend_fudge) #define backend_modify ((loop)->backend_modify) @@ -77,6 +77,12 @@ #define fs_w ((loop)->fs_w) #define fs_2625 ((loop)->fs_2625) #define fs_hash ((loop)->fs_hash) +#define loop_count ((loop)->loop_count) +#define loop_depth ((loop)->loop_depth) +#define userdata ((loop)->userdata) +#define release_cb ((loop)->release_cb) +#define acquire_cb ((loop)->acquire_cb) +#define invoke_cb ((loop)->invoke_cb) #else #undef EV_WRAP_H #undef now_floor @@ -86,7 +92,7 @@ #undef timeout_blocktime #undef backend #undef activecnt -#undef loop_count +#undef loop_done #undef backend_fd #undef backend_fudge #undef backend_modify @@ -155,4 +161,10 @@ #undef fs_w #undef fs_2625 #undef fs_hash +#undef loop_count +#undef loop_depth +#undef userdata +#undef release_cb +#undef acquire_cb +#undef invoke_cb #endif