--- libev/ev.pod 2008/10/23 06:30:48 1.198 +++ libev/ev.pod 2008/10/26 00:52:51 1.203 @@ -12,7 +12,7 @@ #include // every watcher type has its own typedef'd struct - // with the name ev_ + // with the name ev_TYPE ev_io stdin_watcher; ev_timer timeout_watcher; @@ -278,9 +278,13 @@ =head1 FUNCTIONS CONTROLLING THE EVENT LOOP -An event loop is described by a C. The library knows two -types of such loops, the I loop, which supports signals and child -events, and dynamically created loops which do not. +An event loop is described by a C (the C +is I optional in this case, as there is also an C +I). + +The library knows two types of such loops, the I loop, which +supports signals and child events, and dynamically created loops which do +not. =over 4 @@ -529,9 +533,9 @@ the easiest thing, you can just ignore the watchers and/or C them for example). -Note that certain global state, such as signal state, will not be freed by -this function, and related watchers (such as signal and child watchers) -would need to be stopped manually. +Note that certain global state, such as signal state (and installed signal +handlers), will not be freed by this function, and related watchers (such +as signal and child watchers) would need to be stopped manually. In general it is not advisable to call this function except in the rare occasion where you really need to free e.g. the signal handling @@ -770,7 +774,7 @@ =item ev_loop_verify (loop) This function only does something when C support has been -compiled in. which is the default for non-minimal builds. It tries to go +compiled in, which is the default for non-minimal builds. It tries to go through all internal structures and checks them for validity. If anything is found to be inconsistent, it will print an error message to standard error and call C. @@ -784,6 +788,10 @@ =head1 ANATOMY OF A WATCHER +In the following description, uppercase C in names stands for the +watcher type, e.g. C can mean C for timer +watchers and C for I/O watchers. + A watcher is a structure that you create and register to record your interest in some event. For instance, if you want to wait for STDIN to become readable, you would create an C watcher for that: @@ -795,15 +803,21 @@ } struct ev_loop *loop = ev_default_loop (0); + ev_io stdin_watcher; + ev_init (&stdin_watcher, my_cb); ev_io_set (&stdin_watcher, STDIN_FILENO, EV_READ); ev_io_start (loop, &stdin_watcher); + ev_loop (loop, 0); As you can see, you are responsible for allocating the memory for your -watcher structures (and it is usually a bad idea to do this on the stack, -although this can sometimes be quite valid). +watcher structures (and it is I a bad idea to do this on the +stack). + +Each watcher has an associated watcher structure (called C +or simply C, as typedefs are provided for all watcher structs). Each watcher structure must be initialised by a call to C, which expects a callback to be provided. This @@ -811,19 +825,19 @@ watchers, each time the event loop detects that the file descriptor given is readable and/or writable). -Each watcher type has its own C<< ev__set (watcher *, ...) >> macro -with arguments specific to this watcher type. There is also a macro -to combine initialisation and setting in one call: C<< ev__init -(watcher *, callback, ...) >>. +Each watcher type further has its own C<< ev_TYPE_set (watcher *, ...) >> +macro to configure it, with arguments specific to the watcher type. There +is also a macro to combine initialisation and setting in one call: C<< +ev_TYPE_init (watcher *, callback, ...) >>. To make the watcher actually watch out for events, you have to start it -with a watcher-specific start function (C<< ev__start (loop, watcher +with a watcher-specific start function (C<< ev_TYPE_start (loop, watcher *) >>), and you can stop watching for events at any time by calling the -corresponding stop function (C<< ev__stop (loop, watcher *) >>. +corresponding stop function (C<< ev_TYPE_stop (loop, watcher *) >>. As long as your watcher is active (has been started but not stopped) you must not touch the values stored in it. Most specifically you must never -reinitialise it or call its C macro. +reinitialise it or call its C macro. Each and every callback receives the event loop pointer as first, the registered watcher structure as second, and a bitset of received events as @@ -914,9 +928,6 @@ =head2 GENERIC WATCHER FUNCTIONS -In the following description, C stands for the watcher type, -e.g. C for C watchers and C for C watchers. - =over 4 =item C (ev_TYPE *watcher, callback) @@ -1034,7 +1045,7 @@ Setting a priority outside the range of C to C is fine, as long as you do not mind that the priority value you query might -or might not have been adjusted to be within valid range. +or might not have been clamped to the valid range. =item ev_invoke (loop, ev_TYPE *watcher, int revents) @@ -1290,20 +1301,20 @@ =head3 Be smart about timeouts -Many real-world problems invole some kind of time-out, usually for error +Many real-world problems involve some kind of timeout, usually for error recovery. A typical example is an HTTP request - if the other side hangs, you want to raise some error after a while. -Here are some ways on how to handle this problem, from simple and -inefficient to very efficient. +What follows are some ways to handle this problem, from obvious and +inefficient to smart and efficient. -In the following examples a 60 second activity timeout is assumed - a -timeout that gets reset to 60 seconds each time some data ("a lifesign") -was received. +In the following, a 60 second activity timeout is assumed - a timeout that +gets reset to 60 seconds each time there is activity (e.g. each time some +data or other life sign was received). =over 4 -=item 1. Use a timer and stop, reinitialise, start it on activity. +=item 1. Use a timer and stop, reinitialise and start it on activity. This is the most obvious, but not the most simple way: In the beginning, start the watcher: @@ -1311,55 +1322,61 @@ ev_timer_init (timer, callback, 60., 0.); ev_timer_start (loop, timer); -Then, each time there is some activity, C the timer, -initialise it again, and start it: +Then, each time there is some activity, C it, initialise it +and start it again: ev_timer_stop (loop, timer); ev_timer_set (timer, 60., 0.); ev_timer_start (loop, timer); -This is relatively simple to implement, but means that each time there -is some activity, libev will first have to remove the timer from it's -internal data strcuture and then add it again. +This is relatively simple to implement, but means that each time there is +some activity, libev will first have to remove the timer from its internal +data structure and then add it again. Libev tries to be fast, but it's +still not a constant-time operation. =item 2. Use a timer and re-start it with C inactivity. This is the easiest way, and involves using C instead of C. -For this, configure an C with a C value of C<60> and -then call C at start and each time you successfully read -or write some data. If you go into an idle state where you do not expect -data to travel on the socket, you can C the timer, and -C will automatically restart it if need be. - -That means you can ignore the C value and C -altogether and only ever use the C value and C. +To implement this, configure an C with a C value +of C<60> and then call C at start and each time you +successfully read or write some data. If you go into an idle state where +you do not expect data to travel on the socket, you can C +the timer, and C will automatically restart it if need be. + +That means you can ignore both the C function and the +C argument to C, and only ever use the C +member and C. At start: - ev_timer_init (timer, callback, 0., 60.); + ev_timer_init (timer, callback); + timer->repeat = 60.; ev_timer_again (loop, timer); -Each time you receive some data: +Each time there is some activity: ev_timer_again (loop, timer); -It is even possible to change the time-out on the fly: +It is even possible to change the time-out on the fly, regardless of +whether the watcher is active or not: timer->repeat = 30.; ev_timer_again (loop, timer); This is slightly more efficient then stopping/starting the timer each time you want to modify its timeout value, as libev does not have to completely -remove and re-insert the timer from/into it's internal data structure. +remove and re-insert the timer from/into its internal data structure. + +It is, however, even simpler than the "obvious" way to do it. =item 3. Let the timer time out, but then re-arm it as required. This method is more tricky, but usually most efficient: Most timeouts are -relatively long compared to the loop iteration time - in our example, -within 60 seconds, there are usually many I/O events with associated -activity resets. +relatively long compared to the intervals between other activity - in +our example, within 60 seconds, there are usually many I/O events with +associated activity resets. In this case, it would be more efficient to leave the C alone, but remember the time of last activity, and check for a real timeout only @@ -1370,10 +1387,10 @@ static void callback (EV_P_ ev_timer *w, int revents) { - ev_tstamp now = ev_now (EV_A); + ev_tstamp now = ev_now (EV_A); ev_tstamp timeout = last_activity + 60.; - // if last_activity is older than now - timeout, we did time out + // if last_activity + 60. is older than now, we did time out if (timeout < now) { // timeout occured, take action @@ -1381,41 +1398,82 @@ else { // callback was invoked, but there was some activity, re-arm - // to fire in last_activity + 60. + // the watcher to fire in last_activity + 60, which is + // guaranteed to be in the future, so "again" is positive: w->again = timeout - now; ev_timer_again (EV_A_ w); } } -To summarise the callback: first calculate the real time-out (defined as -"60 seconds after the last activity"), then check if that time has been -reached, which means there was a real timeout. Otherwise the callback was -invoked too early (timeout is in the future), so re-schedule the timer to -fire at that future time. +To summarise the callback: first calculate the real timeout (defined +as "60 seconds after the last activity"), then check if that time has +been reached, which means something I, in fact, time out. Otherwise +the callback was invoked too early (C is in the future), so +re-schedule the timer to fire at that future time, to see if maybe we have +a timeout then. Note how C is used, taking advantage of the C optimisation when the timer is already running. -This scheme causes more callback invocations (about one every 60 seconds), -but virtually no calls to libev to change the timeout. - -To start the timer, simply intiialise the watcher and C, -then call the callback: +This scheme causes more callback invocations (about one every 60 seconds +minus half the average time between activity), but virtually no calls to +libev to change the timeout. + +To start the timer, simply initialise the watcher and set C +to the current time (meaning we just have some activity :), then call the +callback, which will "do the right thing" and start the timer: ev_timer_init (timer, callback); last_activity = ev_now (loop); callback (loop, timer, EV_TIMEOUT); -And when there is some activity, simply remember the time in -C: +And when there is some activity, simply store the current time in +C, no libev calls at all: last_actiivty = ev_now (loop); This technique is slightly more complex, but in most cases where the time-out is unlikely to be triggered, much more efficient. +Changing the timeout is trivial as well (if it isn't hard-coded in the +callback :) - just change the timeout and invoke the callback, which will +fix things for you. + +=item 4. Wee, just use a double-linked list for your timeouts. + +If there is not one request, but many thousands (millions...), all +employing some kind of timeout with the same timeout value, then one can +do even better: + +When starting the timeout, calculate the timeout value and put the timeout +at the I of the list. + +Then use an C to fire when the timeout at the I of +the list is expected to fire (for example, using the technique #3). + +When there is some activity, remove the timer from the list, recalculate +the timeout, append it to the end of the list again, and make sure to +update the C if it was taken from the beginning of the list. + +This way, one can manage an unlimited number of timeouts in O(1) time for +starting, stopping and updating the timers, at the expense of a major +complication, and having to use a constant timeout. The constant timeout +ensures that the list stays sorted. + =back +So which method the best? + +Method #2 is a simple no-brain-required solution that is adequate in most +situations. Method #3 requires a bit more thinking, but handles many cases +better, and isn't very complicated either. In most case, choosing either +one is fine, with #3 being better in typical situations. + +Method #1 is almost always a bad idea, and buys you nothing. Method #4 is +rather complicated, but extremely efficient, something that really pays +off after the first million or so of active timers, i.e. it's usually +overkill :) + =head3 The special problem of time updates Establishing the current time is a costly operation (it usually takes at @@ -2902,6 +2960,11 @@ Leandro Lucarella has written a D language binding (F) for libev, to be found at L. +=item Ocaml + +Erkki Seppala has written Ocaml bindings for libev, to be found at +L. + =back