--- libev/ev.pod 2011/08/13 17:41:14 1.381 +++ libev/ev.pod 2011/12/20 04:08:35 1.388 @@ -176,7 +176,7 @@ Returns the current time as libev would use it. Please note that the C function is usually faster and also often returns the timestamp you actually want to know. Also interesting is the combination of -C and C. +C and C. =item ev_sleep (ev_tstamp interval) @@ -1022,7 +1022,7 @@ However, C can run an indefinite time, so it is not feasible to wait for it to return. One way around this is to wake up the event -loop via C and C, another way is to set these +loop via C and C, another way is to set these I and I callbacks on the loop. When set, then C will be called just before the thread is @@ -1862,63 +1862,77 @@ but remember the time of last activity, and check for a real timeout only within the callback: + ev_tstamp timeout = 60.; ev_tstamp last_activity; // time of last activity + ev_timer timer; static void callback (EV_P_ ev_timer *w, int revents) { - ev_tstamp now = ev_now (EV_A); - ev_tstamp timeout = last_activity + 60.; + // calculate when the timeout would happen + ev_tstamp after = last_activity - ev_now (EV_A) + timeout; - // if last_activity + 60. is older than now, we did time out - if (timeout < now) + // if negative, it means we the timeout already occured + if (after < 0.) { // timeout occurred, take action } else { - // callback was invoked, but there was some activity, re-arm - // the watcher to fire in last_activity + 60, which is - // guaranteed to be in the future, so "again" is positive: - w->repeat = timeout - now; - ev_timer_again (EV_A_ w); + // callback was invoked, but there was some recent + // activity. simply restart the timer to time out + // after "after" seconds, which is the earliest time + // the timeout can occur. + ev_timer_set (w, after, 0.); + ev_timer_start (EV_A_ w); } } -To summarise the callback: first calculate the real timeout (defined -as "60 seconds after the last activity"), then check if that time has -been reached, which means something I, 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. +To summarise the callback: first calculate in how many seconds the +timeout will occur (by calculating the absolute time when it would occur, +C, and subtracting the current time, C from that). + +If this value is negative, then we are already past the timeout, i.e. we +timed out, and need to do whatever is needed in this case. + +Otherwise, we now the earliest time at which the timeout would trigger, +and simply start the timer with this timeout value. + +In other words, each time the callback is invoked it will check whether +the timeout cocured. If not, it will simply reschedule itself to check +again at the earliest time it could time out. Rinse. Repeat. This scheme causes more callback invocations (about one every 60 seconds minus half the average time between activity), but virtually no calls to libev to change the timeout. -To start the timer, simply initialise the watcher and set C -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_init (timer, callback); - last_activity = ev_now (loop); - callback (loop, timer, EV_TIMER); +To start the machinery, simply initialise the watcher and set +C to the current time (meaning there was some activity just +now), then call the callback, which will "do the right thing" and start +the timer: + + last_activity = ev_now (EV_A); + ev_init (&timer, callback); + callback (EV_A_ &timer, 0); -And when there is some activity, simply store the current time in +When there is some activity, simply store the current time in C, no libev calls at all: - last_activity = ev_now (loop); + if (activity detected) + last_activity = ev_now (EV_A); + +When your timeout value changes, then the timeout can be changed by simply +providing a new value, stopping the timer and calling the callback, which +will agaion do the right thing (for example, time out immediately :). + + timeout = new_value; + ev_timer_stop (EV_A_ &timer); + callback (EV_A_ &timer, 0); This technique is slightly more complex, but in most cases where the time-out is unlikely to be triggered, much more efficient. -Changing the timeout is trivial as well (if it isn't hard-coded in the -callback :) - just change the timeout and invoke the callback, which will -fix things for you. - =item 4. Wee, just use a double-linked list for your timeouts. If there is not one request, but many thousands (millions...), all @@ -1960,10 +1974,10 @@ you expect it to be invoked after three seconds - but of course, this cannot be guaranteed to infinite precision. Less obviously, it cannot be guaranteed to any precision by libev - imagine somebody suspending the -process a STOP signal for a few hours for example. +process with a STOP signal for a few hours for example. So, libev tries to invoke your callback as soon as possible I the -delay has occured, but cannot guarantee this. +delay has occurred, but cannot guarantee this. A less obvious failure mode is calling your callback too early: many event loops compare timestamps with a "elapsed delay >= requested delay", but @@ -1993,8 +2007,8 @@ =head3 The special problem of time updates -Establishing the current time is a costly operation (it usually takes at -least two system calls): EV therefore updates its idea of the current +Establishing the current time is a costly operation (it usually takes +at least one system call): EV therefore updates its idea of the current time only before and after C collects new events, which causes a growing difference between C and C when handling lots of events in one iteration. @@ -2011,7 +2025,7 @@ update of the time returned by C by calling C. -=head3 The special problem of unsychronised clocks +=head3 The special problem of unsynchronised clocks Modern systems have a variety of clocks - libev itself uses the normal "wall clock" clock and, if available, the monotonic clock (to avoid time @@ -2025,7 +2039,7 @@ The moral of this is to only compare libev-related timestamps with C and C, at least if you want better precision than -a seocnd or so. +a second or so. One more problem arises due to this lack of synchronisation: if libev uses the system monotonic clock and you compare timestamps from C @@ -3475,7 +3489,7 @@ =item ev_feed_fd_event (loop, int fd, int revents) Feed an event on the given fd, as if a file descriptor backend detected -the given events it. +the given events. =item ev_feed_signal_event (loop, int signum) @@ -3559,6 +3573,46 @@ (((char *)w) - offsetof (struct my_biggy, t2)); } +=head2 AVOIDING FINISHING BEFORE RETURNING + +Often you have structures like this in event-based programs: + + callback () + { + free (request); + } + + request = start_new_request (..., callback); + +The intent is to start some "lengthy" operation. The C could be +used to cancel the operation, or do other things with it. + +It's not uncommon to have code paths in C that +immediately invoke the callback, for example, to report errors. Or you add +some caching layer that finds that it can skip the lengthy aspects of the +operation and simply invoke the callback with the result. + +The problem here is that this will happen I C +has returned, so C is not set. + +Even if you pass the request by some safer means to the callback, you +might want to do something to the request after starting it, such as +canceling it, which probably isn't working so well when the callback has +already been invoked. + +A common way around all these issues is to make sure that +C I returns before the callback is invoked. If +C immediately knows the result, it can artificially +delay invoking the callback by e.g. using a C or C watcher +for example, or more sneakily, by reusing an existing (stopped) watcher +and pushing it into the pending queue: + + ev_set_cb (watcher, callback); + ev_feed_event (EV_A_ watcher, 0); + +This way, C can safely return before the callback is +invoked, while not delaying callback invocation too much. + =head2 MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS Often (especially in GUI toolkits) there are places where you have @@ -4600,6 +4654,17 @@ your program might be left out as well - a binary starting a timer and an I/O watcher then might come out at only 5Kb. +=item EV_API_STATIC + +If this symbol is defined (by default it is not), then all identifiers +will have static linkage. This means that libev will not export any +identifiers, and you cannot link against libev anymore. This can be useful +when you embed libev, only want to use libev functions in a single file, +and do not want its identifiers to be visible. + +To use this, define C and include F in the file that +wants to use libev. + =item EV_AVOID_STDIO If this is set to C<1> at compiletime, then libev will avoid using stdio @@ -5134,7 +5199,7 @@ implementations using IEEE 754, which is basically all existing ones. With IEEE 754 doubles, you get microsecond accuracy until at least the -year 2255 (and millisecond accuray till the year 287396 - by then, libev +year 2255 (and millisecond accuracy till the year 287396 - by then, libev is either obsolete or somebody patched it to use C or something like that, just kidding).