--- libev/ev.pod 2011/12/19 20:15:28 1.386 +++ libev/ev.pod 2011/12/20 20:04:51 1.392 @@ -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 @@ -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 @@ -3581,7 +3635,7 @@ while (!exit_main_loop) ev_run (EV_DEFAULT_ EVRUN_ONCE); - // in a model watcher + // in a modal watcher int exit_nested_loop = 0; while (!exit_nested_loop) @@ -3771,7 +3825,7 @@ That basically suspends the coroutine inside C and continues the libev coroutine, which, when appropriate, switches back to -this or any other coroutine. I am sure if you sue this your own :) +this or any other coroutine. You can do similar tricks if you have, say, threads with an event queue - instead of storing a coroutine, you store the queue object and instead of @@ -3874,7 +3928,7 @@ For each C watcher in F there is a corresponding class of the same name in the C namespace, with the exception of C which is called C to avoid clashes with the C macro -defines by many implementations. +defined by many implementations. All of those classes have these methods: @@ -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