=encoding utf-8 =head1 NAME libev - a high performance full-featured event loop written in C =head1 SYNOPSIS #include =head2 EXAMPLE PROGRAM // a single header file is required #include #include // for puts // every watcher type has its own typedef'd struct // with the name ev_TYPE ev_io stdin_watcher; ev_timer timeout_watcher; // all watcher callbacks have a similar signature // this callback is called when data is readable on stdin static void stdin_cb (EV_P_ ev_io *w, int revents) { puts ("stdin ready"); // for one-shot events, one must manually stop the watcher // with its corresponding stop function. ev_io_stop (EV_A_ w); // this causes all nested ev_run's to stop iterating ev_break (EV_A_ EVBREAK_ALL); } // another callback, this time for a time-out static void timeout_cb (EV_P_ ev_timer *w, int revents) { puts ("timeout"); // this causes the innermost ev_run to stop iterating ev_break (EV_A_ EVBREAK_ONE); } int main (void) { // use the default event loop unless you have special needs struct ev_loop *loop = EV_DEFAULT; // initialise an io watcher, then start it // this one will watch for stdin to become readable ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ); ev_io_start (loop, &stdin_watcher); // initialise a timer watcher, then start it // simple non-repeating 5.5 second timeout ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); ev_timer_start (loop, &timeout_watcher); // now wait for events to arrive ev_run (loop, 0); // break was called, so exit return 0; } =head1 ABOUT THIS DOCUMENT This document documents the libev software package. The newest version of this document is also available as an html-formatted web page you might find easier to navigate when reading it for the first time: L. While this document tries to be as complete as possible in documenting libev, its usage and the rationale behind its design, it is not a tutorial on event-based programming, nor will it introduce event-based programming with libev. Familiarity with event based programming techniques in general is assumed throughout this document. =head1 WHAT TO READ WHEN IN A HURRY This manual tries to be very detailed, but unfortunately, this also makes it very long. If you just want to know the basics of libev, I suggest reading L, then the L above and look up the missing functions in L and the C and C sections in L. =head1 ABOUT LIBEV Libev is an event loop: you register interest in certain events (such as a file descriptor being readable or a timeout occurring), and it will manage these event sources and provide your program with events. To do this, it must take more or less complete control over your process (or thread) by executing the I handler, and will then communicate events via a callback mechanism. You register interest in certain events by registering so-called I, which are relatively small C structures you initialise with the details of the event, and then hand it over to libev by I the watcher. =head2 FEATURES Libev supports C (files, many character devices...). Epoll is truly the train wreck among event poll mechanisms, a frankenpoll, cobbled together in a hurry, no thought to design or interaction with others. Oh, the pain, will it ever stop... While stopping, setting and starting an I/O watcher in the same iteration will result in some caching, there is still a system call per such incident (because the same I could point to a different I now), so its best to avoid that. Also, C'ed file descriptors might not work very well if you register events for both file descriptors. Best performance from this backend is achieved by not unregistering all watchers for a file descriptor until it has been closed, if possible, i.e. keep at least one watcher active per fd at all times. Stopping and starting a watcher (without re-setting it) also usually doesn't cause extra overhead. A fork can both result in spurious notifications as well as in libev having to destroy and recreate the epoll object, which can take considerable time and thus should be avoided. All this means that, in practice, C can be as fast or faster than epoll for maybe up to a hundred file descriptors, depending on the usage. So sad. While nominally embeddable in other event loops, this feature is broken in all kernel versions tested so far. This backend maps C and C in the same way as C. =item C (value 8, most BSD clones) Kqueue deserves special mention, as at the time of this writing, it was broken on all BSDs except NetBSD (usually it doesn't work reliably with anything but sockets and pipes, except on Darwin, where of course it's completely useless). Unlike epoll, however, whose brokenness is by design, these kqueue bugs can (and eventually will) be fixed without API changes to existing programs. For this reason it's not being "auto-detected" unless you explicitly specify it in the flags (i.e. using C) or libev was compiled on a known-to-be-good (-enough) system like NetBSD. You still can embed kqueue into a normal poll or select backend and use it only for sockets (after having made sure that sockets work with kqueue on the target platform). See C watchers for more info. It scales in the same way as the epoll backend, but the interface to the kernel is more efficient (which says nothing about its actual speed, of course). While stopping, setting and starting an I/O watcher does never cause an extra system call as with C, it still adds up to two event changes per incident. Support for C is very bad (you might have to leak fd's on fork, but it's more sane than epoll) and it drops fds silently in similarly hard-to-detect cases. This backend usually performs well under most conditions. While nominally embeddable in other event loops, this doesn't work everywhere, so you might need to test for this. And since it is broken almost everywhere, you should only use it when you have a lot of sockets (for which it usually works), by embedding it into another event loop (e.g. C or C (but C is of course also broken on OS X)) and, did I mention it, using it only for sockets. This backend maps C into an C kevent with C, and C into an C kevent with C. =item C (value 16, Solaris 8) This is not implemented yet (and might never be, unless you send me an implementation). According to reports, C only supports sockets and is not embeddable, which would limit the usefulness of this backend immensely. =item C (value 32, Solaris 10) This uses the Solaris 10 event port mechanism. As with everything on Solaris, it's really slow, but it still scales very well (O(active_fds)). While this backend scales well, it requires one system call per active file descriptor per loop iteration. For small and medium numbers of file descriptors a "slow" C or C backend might perform better. On the positive side, this backend actually performed fully to specification in all tests and is fully embeddable, which is a rare feat among the OS-specific backends (I vastly prefer correctness over speed hacks). On the negative side, the interface is I - so bizarre that even sun itself gets it wrong in their code examples: The event polling function sometimes returns events to the caller even though an error occurred, but with no indication whether it has done so or not (yes, it's even documented that way) - deadly for edge-triggered interfaces where you absolutely have to know whether an event occurred or not because you have to re-arm the watcher. Fortunately libev seems to be able to work around these idiocies. This backend maps C and C in the same way as C. =item C Try all backends (even potentially broken ones that wouldn't be tried with C). Since this is a mask, you can do stuff such as C. It is definitely not recommended to use this flag, use whatever C returns, or simply do not specify a backend at all. =item C Not a backend at all, but a mask to select all backend bits from a C value, in case you want to mask out any backends from a flags value (e.g. when modifying the C environment variable). =back If one or more of the backend flags are or'ed into the flags value, then only these backends will be tried (in the reverse order as listed here). If none are specified, all backends in C will be tried. Example: Try to create a event loop that uses epoll and nothing else. struct ev_loop *epoller = ev_loop_new (EVBACKEND_EPOLL | EVFLAG_NOENV); if (!epoller) fatal ("no epoll found here, maybe it hides under your chair"); Example: Use whatever libev has to offer, but make sure that kqueue is used if available. struct ev_loop *loop = ev_loop_new (ev_recommended_backends () | EVBACKEND_KQUEUE); =item ev_loop_destroy (loop) Destroys an event loop object (frees all memory and kernel state etc.). None of the active event watchers will be stopped in the normal sense, so e.g. C might still return true. It is your responsibility to either stop all watchers cleanly yourself I calling this function, or cope with the fact afterwards (which is usually the easiest thing, you can just ignore the watchers and/or C them for example). 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. This function is normally used on loop objects allocated by C, but it can also be used on the default loop returned by C, in which case it is not thread-safe. Note that it is not advisable to call this function on the default loop except in the rare occasion where you really need to free its resources. If you need dynamically allocated loops it is better to use C and C. =item ev_loop_fork (loop) This function sets a flag that causes subsequent C iterations to reinitialise the kernel state for backends that have one. Despite the name, you can call it anytime, but it makes most sense after forking, in the child process. You I call it (or use C) in the child before resuming or calling C. Again, you I to call it on I loop that you want to re-use after a fork, I. This is because some kernel interfaces *cough* I *cough* do funny things during fork. On the other hand, you only need to call this function in the child process if and only if you want to use the event loop in the child. If you just fork+exec or create a new loop in the child, you don't have to call it at all (in fact, C is so badly broken that it makes a difference, but libev will usually detect this case on its own and do a costly reset of the backend). The function itself is quite fast and it's usually not a problem to call it just in case after a fork. Example: Automate calling C on the default loop when using pthreads. static void post_fork_child (void) { ev_loop_fork (EV_DEFAULT); } ... pthread_atfork (0, 0, post_fork_child); =item int ev_is_default_loop (loop) Returns true when the given loop is, in fact, the default loop, and false otherwise. =item unsigned int ev_iteration (loop) Returns the current iteration count for the event loop, which is identical to the number of times libev did poll for new events. It starts at C<0> and happily wraps around with enough iterations. This value can sometimes be useful as a generation counter of sorts (it "ticks" the number of loop iterations), as it roughly corresponds with C and C calls - and is incremented between the prepare and check phases. =item unsigned int ev_depth (loop) Returns the number of times C was entered minus the number of times C was exited normally, in other words, the recursion depth. Outside C, this number is zero. In a callback, this number is C<1>, unless C was invoked recursively (or from another thread), in which case it is higher. Leaving C abnormally (setjmp/longjmp, cancelling the thread, throwing an exception etc.), doesn't count as "exit" - consider this as a hint to avoid such ungentleman-like behaviour unless it's really convenient, in which case it is fully supported. =item unsigned int ev_backend (loop) Returns one of the C flags indicating the event backend in use. =item ev_tstamp ev_now (loop) Returns the current "event loop time", which is the time the event loop received events and started processing them. This timestamp does not change as long as callbacks are being processed, and this is also the base time used for relative timers. You can treat it as the timestamp of the event occurring (or more correctly, libev finding out about it). =item ev_now_update (loop) Establishes the current time by querying the kernel, updating the time returned by C in the progress. This is a costly operation and is usually done automatically within C. This function is rarely useful, but when some event callback runs for a very long time without entering the event loop, updating libev's idea of the current time is a good idea. See also L in the C section. =item ev_suspend (loop) =item ev_resume (loop) These two functions suspend and resume an event 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 occurred 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 bool ev_run (loop, int flags) Finally, this is it, the event handler. This function usually is called after you have initialised all your watchers and you want to start handling events. It will ask the operating system for any new events, call the watcher callbacks, and then repeat the whole process indefinitely: This is why event loops are called I. If the flags argument is specified as C<0>, it will keep handling events until either no event watchers are active anymore or C was called. The return value is false if there are no more active watchers (which usually means "all jobs done" or "deadlock"), and true in all other cases (which usually means " you should call C again"). Please note that an explicit C is usually better than relying on all watchers to be stopped when deciding when a program has finished (especially in interactive programs), but having a program that automatically loops as long as it has to and no longer by virtue of relying on its watchers stopping correctly, that is truly a thing of beauty. This function is I exception-safe - you can break out of a C call by calling C in a callback, throwing a C++ exception and so on. This does not decrement the C value, nor will it clear any outstanding C breaks. A flags value of C will look for new events, will handle those events and any already outstanding ones, but will not wait and block your process in case there are no events and will return after one iteration of the loop. This is sometimes useful to poll and handle new events while doing lengthy calculations, to keep the program responsive. A flags value of C will look for new events (waiting if necessary) and will handle those and any already outstanding ones. It will block your process until at least one new event arrives (which could be an event internal to libev itself, so there is no guarantee that a user-registered callback will be called), and will return after one iteration of the loop. This is useful if you are waiting for some external event in conjunction with something not expressible using other libev watchers (i.e. "roll your own C"). However, a pair of C/C watchers is usually a better approach for this kind of thing. Here are the gory details of what C does (this is for your understanding, not a guarantee that things will work exactly like this in future versions): - Increment loop depth. - Reset the ev_break status. - Before the first iteration, call any pending watchers. LOOP: - If EVFLAG_FORKCHECK was used, check for a fork. - If a fork was detected (by any means), queue and call all fork watchers. - Queue and call all prepare watchers. - If ev_break was called, goto FINISH. - If we have been forked, detach and recreate the kernel state as to not disturb the other process. - Update the kernel state with all outstanding changes. - Update the "event loop time" (ev_now ()). - Calculate for how long to sleep or block, if at all (active idle watchers, EVRUN_NOWAIT or not having any active watchers at all will result in not sleeping). - Sleep if the I/O and timer collect interval say so. - Increment loop iteration counter. - Block the process, waiting for any events. - Queue all outstanding I/O (fd) events. - Update the "event loop time" (ev_now ()), and do time jump adjustments. - Queue all expired timers. - Queue all expired periodics. - Queue all idle watchers with priority higher than that of pending events. - Queue all check watchers. - Call all queued watchers in reverse order (i.e. check watchers first). Signals and child watchers are implemented as I/O watchers, and will be handled here by queueing them when their watcher gets executed. - If ev_break has been called, or EVRUN_ONCE or EVRUN_NOWAIT were used, or there are no active watchers, goto FINISH, otherwise continue with step LOOP. FINISH: - Reset the ev_break status iff it was EVBREAK_ONE. - Decrement the loop depth. - Return. Example: Queue some jobs and then loop until no events are outstanding anymore. ... queue jobs here, make sure they register event watchers as long ... as they still have work to do (even an idle watcher will do..) ev_run (my_loop, 0); ... jobs done or somebody called break. yeah! =item ev_break (loop, how) Can be used to make a call to C return early (but only after it has processed all outstanding events). The C argument must be either C, which will make the innermost C call return, or C, which will make all nested C calls return. This "break state" will be cleared on the next call to C. It is safe to call C from outside any C calls, too, in which case it will have no effect. =item ev_ref (loop) =item ev_unref (loop) Ref/unref can be used to add or remove a reference count on the event loop: Every watcher keeps one reference, and as long as the reference count is nonzero, C will not return on its own. This is useful when you have a watcher that you never intend to unregister, but that nevertheless should not keep C from returning. In such a case, call C after starting, and C 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. 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. ev_signal exitsig; ev_signal_init (&exitsig, sig_cb, SIGINT); ev_signal_start (loop, &exitsig); ev_unref (loop); Example: For some weird reason, unregister the above signal handler again. ev_ref (loop); ev_signal_stop (loop, &exitsig); =item ev_set_io_collect_interval (loop, ev_tstamp interval) =item ev_set_timeout_collect_interval (loop, ev_tstamp interval) These advanced functions influence the time that libev will spend waiting for events. Both time intervals are by default C<0>, meaning that libev will try to invoke timer/periodic callbacks and I/O callbacks with minimum latency. Setting these to a higher value (the C I be >= C<0>) allows libev to delay invocation of I/O and timer/periodic callbacks to increase efficiency of loop iterations (or to increase power-saving opportunities). The idea is that sometimes your program runs just fast enough to handle one (or very few) event(s) per loop iteration. While this makes the program responsive, it also wastes a lot of CPU time to poll for new events, especially with backends like C (or libev) on file descriptors representing files, and expect it to become ready when their program doesn't block on disk accesses (which can take a long time on their own). However, this cannot ever work in the "expected" way - you get a readiness notification as soon as the kernel knows whether and how much data is there, and in the case of open files, that's always the case, so you always get a readiness notification instantly, and your read (or possibly write) will still block on the disk I/O. Another way to view it is that in the case of sockets, pipes, character devices and so on, there is another party (the sender) that delivers data on its own, but in the case of files, there is no such thing: the disk will not send data on its own, simply because it doesn't know what you wish to read - you would first have to request some data. Since files are typically not-so-well supported by advanced notification mechanism, libev tries hard to emulate POSIX behaviour with respect to files, even though you should not use it. The reason for this is convenience: sometimes you want to watch STDIN or STDOUT, which is usually a tty, often a pipe, but also sometimes files or special devices (for example, C on Linux works with F but not with F), and even though the file might better be served with asynchronous I/O instead of with non-blocking I/O, it is still useful when it "just works" instead of freezing. So avoid file descriptors pointing to files when you know it (e.g. use libeio), but use them when it is convenient, e.g. for STDIN/STDOUT, or when you rarely read from a file instead of from a socket, and want to reuse the same code path. =head3 The special problem of fork Some backends (epoll, kqueue) do not support C at all or exhibit useless behaviour. Libev fully supports fork, but needs to be told about it in the child if you want to continue to use it in the child. To support fork in your child processes, you have to call C after a fork in the child, enable C, or resort to C or C. =head3 The special problem of SIGPIPE While not really specific to libev, it is easy to forget about C: when writing to a pipe whose other end has been closed, your program gets sent a SIGPIPE, which, by default, aborts your program. For most programs this is sensible behaviour, for daemons, this is usually undesirable. So when you encounter spurious, unexplained daemon exits, make sure you ignore SIGPIPE (and maybe make sure you log the exit status of your daemon somewhere, as that would have given you a big clue). =head3 The special problem of accept()ing when you can't Many implementations of the POSIX C function (for example, found in post-2004 Linux) have the peculiar behaviour of not removing a connection from the pending queue in all error cases. For example, larger servers often run out of file descriptors (because of resource limits), causing C to fail with C but not rejecting the connection, leading to libev signalling readiness on the next iteration again (the connection still exists after all), and typically causing the program to loop at 100% CPU usage. Unfortunately, the set of errors that cause this issue differs between operating systems, there is usually little the app can do to remedy the situation, and no known thread-safe method of removing the connection to cope with overload is known (to me). One of the easiest ways to handle this situation is to just ignore it - when the program encounters an overload, it will just loop until the situation is over. While this is a form of busy waiting, no OS offers an event-based way to handle this situation, so it's the best one can do. A better way to handle the situation is to log any errors other than C and C, making sure not to flood the log with such messages, and continue as usual, which at least gives the user an idea of what could be wrong ("raise the ulimit!"). For extra points one could stop the C watcher on the listening fd "for a while", which reduces CPU usage. If your program is single-threaded, then you could also keep a dummy file descriptor for overload situations (e.g. by opening F), and when you run into C or C, close it, run C, close that fd, and create a new dummy fd. This will gracefully refuse clients under typical overload conditions. The last way to handle it is to simply log the error and C, as is often done with C failures, but this results in an easy opportunity for a DoS attack. =head3 Watcher-Specific Functions =over 4 =item ev_io_init (ev_io *, callback, int fd, int events) =item ev_io_set (ev_io *, int fd, int events) Configures an C watcher. The C is the file descriptor to receive events for and C is either C, C or C, to express the desire to receive the given events. =item int fd [read-only] The file descriptor being watched. =item int events [read-only] The events being watched. =back =head3 Examples Example: Call C when STDIN_FILENO has become, well readable, but only once. Since it is likely line-buffered, you could attempt to read a whole line in the callback. static void stdin_readable_cb (struct ev_loop *loop, ev_io *w, int revents) { ev_io_stop (loop, w); .. read from stdin here (or from w->fd) and handle any I/O errors } ... struct ev_loop *loop = ev_default_init (0); ev_io stdin_readable; ev_io_init (&stdin_readable, stdin_readable_cb, STDIN_FILENO, EV_READ); ev_io_start (loop, &stdin_readable); ev_run (loop, 0); =head2 C - 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. The timers are based on real time, that is, if you register an event that times out after an hour and you reset your system clock to January last year, it will still time out after (roughly) one hour. "Roughly" because detecting time jumps is hard, and some inaccuracies are unavoidable (the monotonic clock option helps a lot here). The callback is guaranteed to be invoked only I its timeout has passed (not I, so on systems with very low-resolution clocks this might introduce a small delay, see "the special problem of being too early", below). If multiple timers become ready during the same loop iteration then the ones with earlier time-out values are invoked before ones of the same priority with later time-out values (but this is no longer true when a callback calls C recursively). =head3 Be smart about timeouts 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. What follows are some ways to handle this problem, from obvious and inefficient to smart and efficient. 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 and start it on activity. This is the most obvious, but not the most simple way: In the beginning, start the watcher: ev_timer_init (timer, callback, 60., 0.); ev_timer_start (loop, timer); 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 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. 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_init (timer, callback); timer->repeat = 60.; ev_timer_again (loop, timer); Each time there is some activity: ev_timer_again (loop, timer); 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 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 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 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) { // calculate when the timeout would happen ev_tstamp after = last_activity - ev_now (EV_A) + timeout; // if negative, it means we the timeout already occurred if (after < 0.) { // timeout occurred, take action } else { // 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 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 occurred. 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 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); When there is some activity, simply store the current time in C, no libev calls at all: 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 again 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. =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 being too early If you ask a timer to call your callback after three seconds, then 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 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 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 this can cause your callback to be invoked much earlier than you would expect. To see why, imagine a system with a clock that only offers full second resolution (think windows if you can't come up with a broken enough OS yourself). If you schedule a one-second timer at the time 500.9, then the event loop will schedule your timeout to elapse at a system time of 500 (500.9 truncated to the resolution) + 1, or 501. If an event library looks at the timeout 0.1s later, it will see "501 >= 501" and invoke the callback 0.1s after it was started, even though a one-second delay was requested - this is being "too early", despite best intentions. This is the reason why libev will never invoke the callback if the elapsed delay equals the requested delay, but only when the elapsed delay is larger than the requested delay. In the example above, libev would only invoke the callback at system time 502, or 1.1s after the timer was started. So, while libev cannot guarantee that your callback will be invoked exactly when requested, it I and I guarantee that the requested delay has actually elapsed, or in other words, it always errs on the "too late" side of things. =head3 The special problem of time updates 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. The relative timeouts are calculated relative to the C time. This is usually the right thing as this timestamp refers to the time of the event triggering whatever timeout you are modifying/starting. If you suspect event processing to be delayed and you I to base the timeout on the current time, use something like this to adjust for this: ev_timer_set (&timer, after + ev_now () - ev_time (), 0.); If the event loop is suspended for a long time, you can also force an update of the time returned by C by calling C. =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 jumps). Neither of these clocks is synchronised with each other or any other clock on the system, so C might return a considerably different time than C or C