mirror of /home/gitosis/repositories/libev.git
parent
bc656a2010
commit
90919622b5
4
Changes
4
Changes
|
@ -1,8 +1,6 @@
|
|||
Revision history for libev, a high-performance and full-featured event loop.
|
||||
|
||||
TODO: ev_walk
|
||||
TODO: signal handling per 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.
|
||||
|
|
|
@ -23,6 +23,7 @@ ev_fork_stop
|
|||
ev_idle_start
|
||||
ev_idle_stop
|
||||
ev_invoke
|
||||
ev_invoke_pending
|
||||
ev_io_start
|
||||
ev_io_stop
|
||||
ev_loop
|
||||
|
@ -35,6 +36,7 @@ ev_loop_verify
|
|||
ev_now
|
||||
ev_now_update
|
||||
ev_once
|
||||
ev_pending_count
|
||||
ev_periodic_again
|
||||
ev_periodic_start
|
||||
ev_periodic_stop
|
||||
|
@ -44,9 +46,12 @@ ev_recommended_backends
|
|||
ev_ref
|
||||
ev_resume
|
||||
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
|
||||
|
@ -57,9 +62,11 @@ ev_supported_backends
|
|||
ev_suspend
|
||||
ev_time
|
||||
ev_timer_again
|
||||
ev_timer_remaining
|
||||
ev_timer_start
|
||||
ev_timer_stop
|
||||
ev_unloop
|
||||
ev_unref
|
||||
ev_userdata
|
||||
ev_version_major
|
||||
ev_version_minor
|
||||
|
|
448
ev.3
448
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 <ev.h>
|
||||
.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
|
||||
<benchmark> 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"
|
||||
|
|
Loading…
Reference in New Issue