|
|
@ -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" |
|
|
|