--- libev/ev.pod 2009/02/06 20:17:43 1.224 +++ libev/ev.pod 2009/04/16 07:49:23 1.234 @@ -636,6 +636,32 @@ See also "The special problem of time updates" in the C section. +=item ev_suspend (loop) + +=item ev_resume (loop) + +These two functions suspend and resume a loop, for use when the loop is +not used for a while and timeouts should not be processed. + +A typical use case would be an interactive program such as a game: When +the user presses C<^Z> to suspend the game and resumes it an hour later it +would be best to handle timeouts as if no time had actually passed while +the program was suspended. This can be achieved by calling C +in your C handler, sending yourself a C and calling +C directly afterwards to resume timer processing. + +Effectively, all C watchers will be delayed by the time spend +between C and C, and all C watchers +will be rescheduled (that is, they will lose any events that would have +occured while suspended). + +After calling C you B call I function on the +given loop other than C, and you B call C +without a previous call to C. + +Calling C/C has the side effect of updating the +event loop time (see C). + =item ev_loop (loop, int flags) Finally, this is it, the event handler. This function usually is called @@ -728,13 +754,15 @@ from returning, call ev_unref() after starting, and ev_ref() before stopping it. -As an example, libev itself uses this for its internal signal pipe: It is -not visible to the libev user and should not keep C from exiting -if no event watchers registered by it are active. It is also an excellent -way to do this for generic recurring timers or from within third-party -libraries. Just remember to I and I -(but only if the watcher wasn't active before, or was active before, -respectively). +As an example, libev itself uses this for its internal signal pipe: It +is not visible to the libev user and should not keep C from +exiting if no event watchers registered by it are active. It is also an +excellent way to do this for generic recurring timers or from within +third-party libraries. Just remember to I and I (but only if the watcher wasn't active before, or was active +before, respectively. Note also that libev might stop watchers itself +(e.g. non-repeating timers) in which case you have to C +in the callback). Example: Create a signal watcher, but keep it from keeping C running when nothing else is active. @@ -928,6 +956,11 @@ The given async watcher has been asynchronously notified (see C). +=item C + +Not ever sent (or otherwise used) by libev itself, but can be freely used +by libev users to signal watchers (e.g. via C). + =item C An unspecified error has occurred, the watcher has been stopped. This might @@ -1052,24 +1085,22 @@ before watchers with lower priority, but priority will not keep watchers from being executed (except for C watchers). -This means that priorities are I used for ordering callback -invocation after new events have been received. This is useful, for -example, to reduce latency after idling, or more often, to bind two -watchers on the same event and make sure one is called first. - If you need to suppress invocation when higher priority events are pending you need to look at C watchers, which provide this functionality. You I change the priority of a watcher as long as it is active or pending. -The default priority used by watchers when no priority has been set is -always C<0>, which is supposed to not be too high and not be too low :). - 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 clamped to the valid range. +The default priority used by watchers when no priority has been set is +always C<0>, which is supposed to not be too high and not be too low :). + +See L, below, for a more thorough treatment of +priorities. + =item ev_invoke (loop, ev_TYPE *watcher, int revents) Invoke the C with the given C and C. Neither @@ -1154,6 +1185,109 @@ (((char *)w) - offsetof (struct my_biggy, t2)); } +=head2 WATCHER PRIORITY MODELS + +Many event loops support I, which are usually small +integers that influence the ordering of event callback invocation +between watchers in some way, all else being equal. + +In libev, Watcher priorities can be set using C. See its +description for the more technical details such as the actual priority +range. + +There are two common ways how these these priorities are being interpreted +by event loops: + +In the more common lock-out model, higher priorities "lock out" invocation +of lower priority watchers, which means as long as higher priority +watchers receive events, lower priority watchers are not being invoked. + +The less common only-for-ordering model uses priorities solely to order +callback invocation within a single event loop iteration: Higher priority +watchers are invoked before lower priority ones, but they all get invoked +before polling for new events. + +Libev uses the second (only-for-ordering) model for all its watchers +except for idle watchers (which use the lock-out model). + +The rationale behind this is that implementing the lock-out model for +watchers is not well supported by most kernel interfaces, and most event +libraries will just poll for the same events again and again as long as +their callbacks have not been executed, which is very inefficient in the +common case of one high-priority watcher locking out a mass of lower +priority ones. + +Static (ordering) priorities are most useful when you have two or more +watchers handling the same resource: a typical usage example is having an +C watcher to receive data, and an associated C to handle +timeouts. Under load, data might be received while the program handles +other jobs, but since timers normally get invoked first, the timeout +handler will be executed before checking for data. In that case, giving +the timer a lower priority than the I/O watcher ensures that I/O will be +handled first even under adverse conditions (which is usually, but not +always, what you want). + +Since idle watchers use the "lock-out" model, meaning that idle watchers +will only be executed when no same or higher priority watchers have +received events, they can be used to implement the "lock-out" model when +required. + +For example, to emulate how many other event libraries handle priorities, +you can associate an C watcher to each such watcher, and in +the normal watcher callback, you just start the idle watcher. The real +processing is done in the idle watcher callback. This causes libev to +continously poll and process kernel event data for the watcher, but when +the lock-out case is known to be rare (which in turn is rare :), this is +workable. + +Usually, however, the lock-out model implemented that way will perform +miserably under the type of load it was designed to handle. In that case, +it might be preferable to stop the real watcher before starting the +idle watcher, so the kernel will not have to process the event in case +the actual processing will be delayed for considerable time. + +Here is an example of an I/O watcher that should run at a strictly lower +priority than the default, and which should only process data when no +other events are pending: + + ev_idle idle; // actual processing watcher + ev_io io; // actual event watcher + + static void + io_cb (EV_P_ ev_io *w, int revents) + { + // stop the I/O watcher, we received the event, but + // are not yet ready to handle it. + ev_io_stop (EV_A_ w); + + // start the idle watcher to ahndle the actual event. + // it will not be executed as long as other watchers + // with the default priority are receiving events. + ev_idle_start (EV_A_ &idle); + } + + static void + idle-cb (EV_P_ ev_idle *w, int revents) + { + // actual processing + read (STDIN_FILENO, ...); + + // have to start the I/O watcher again, as + // we have handled the event + ev_io_start (EV_P_ &io); + } + + // initialisation + ev_idle_init (&idle, idle_cb); + ev_io_init (&io, io_cb, STDIN_FILENO, EV_READ); + ev_io_start (EV_DEFAULT_ &io); + +In the "real" world, it might also be beneficial to start a timer, so that +low-priority connections can not be locked out forever under load. This +enables your program to keep a lower latency for important connections +during short periods of high load, while not completely locking out less +important ones. + =head1 WATCHER TYPES @@ -1319,8 +1453,10 @@ monotonic clock option helps a lot here). The callback is guaranteed to be invoked only I its timeout has -passed, but if multiple timers become ready during the same loop iteration -then order of execution is undefined. +passed. 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 +C recursively). =head3 Be smart about timeouts @@ -1549,7 +1685,7 @@ If the timer is repeating, either start it if necessary (with the C value), or reset the running timer to the C value. -This sounds a bit complicated, see "Be smart about timeouts", above, for a +This sounds a bit complicated, see L, above, for a usage example. =item ev_tstamp repeat [read-write] @@ -1598,52 +1734,63 @@ Periodic watchers are also timers of a kind, but they are very versatile (and unfortunately a bit complex). -Unlike C's, they are not based on real time (or relative time) -but on wall clock time (absolute time). You can tell a periodic watcher -to trigger after some specific point in time. For example, if you tell a -periodic watcher to trigger in 10 seconds (by specifying e.g. C, that is, an absolute time not a delay) and then reset your system -clock to January of the previous year, then it will take more than year -to trigger the event (unlike an C, which would still trigger -roughly 10 seconds later as it uses a relative timeout). - -Cs can also be used to implement vastly more complex timers, -such as triggering an event on each "midnight, local time", or other -complicated rules. +Unlike C, periodic watchers are not based on real time (or +relative time, the physical time that passes) but on wall clock time +(absolute time, the thing you can read on your calender or clock). The +difference is that wall clock time can run faster or slower than real +time, and time jumps are not uncommon (e.g. when you adjust your +wrist-watch). + +You can tell a periodic watcher to trigger after some specific point +in time: for example, if you tell a periodic watcher to trigger "in 10 +seconds" (by specifying e.g. C, that is, an absolute time +not a delay) and then reset your system clock to January of the previous +year, then it will take a year or more to trigger the event (unlike an +C, which would still trigger roughly 10 seconds after starting +it, as it uses a relative timeout). + +C watchers can also be used to implement vastly more complex +timers, such as triggering an event on each "midnight, local time", or +other complicated rules. This cannot be done with C watchers, as +those cannot react to time jumps. As with timers, the callback is guaranteed to be invoked only when the -time (C) has passed, but if multiple periodic timers become ready -during the same loop iteration, then order of execution is undefined. +point in time where it is supposed to trigger has passed. 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 C recursively). =head3 Watcher-Specific Functions and Data Members =over 4 -=item ev_periodic_init (ev_periodic *, callback, ev_tstamp at, ev_tstamp interval, reschedule_cb) +=item ev_periodic_init (ev_periodic *, callback, ev_tstamp offset, ev_tstamp interval, reschedule_cb) -=item ev_periodic_set (ev_periodic *, ev_tstamp after, ev_tstamp repeat, reschedule_cb) +=item ev_periodic_set (ev_periodic *, ev_tstamp offset, ev_tstamp interval, reschedule_cb) -Lots of arguments, lets sort it out... There are basically three modes of +Lots of arguments, let's sort it out... There are basically three modes of operation, and we will explain them from simplest to most complex: =over 4 -=item * absolute timer (at = time, interval = reschedule_cb = 0) +=item * absolute timer (offset = absolute time, interval = 0, reschedule_cb = 0) In this configuration the watcher triggers an event after the wall clock -time C has passed. It will not repeat and will not adjust when a time -jump occurs, that is, if it is to be run at January 1st 2011 then it will -only run when the system clock reaches or surpasses this time. +time C has passed. It will not repeat and will not adjust when a +time jump occurs, that is, if it is to be run at January 1st 2011 then it +will be stopped and invoked when the system clock reaches or surpasses +this point in time. -=item * repeating interval timer (at = offset, interval > 0, reschedule_cb = 0) +=item * repeating interval timer (offset = offset within interval, interval > 0, reschedule_cb = 0) In this mode the watcher will always be scheduled to time out at the next -C time (for some integer N, which can also be negative) -and then repeat, regardless of any time jumps. +C time (for some integer N, which can also be +negative) and then repeat, regardless of any time jumps. The C +argument is merely an offset into the C periods. This can be used to create timers that do not drift with respect to the -system clock, for example, here is a C that triggers each -hour, on the hour: +system clock, for example, here is an C that triggers each +hour, on the hour (with respect to UTC): ev_periodic_set (&periodic, 0., 3600., 0); @@ -1654,9 +1801,9 @@ Another way to think about it (for the mathematically inclined) is that C will try to run the callback in this mode at the next possible -time where C