--- libev/ev.pod 2007/12/22 11:49:17 1.100 +++ libev/ev.pod 2008/04/24 01:42:11 1.148 @@ -6,51 +6,65 @@ #include -=head1 EXAMPLE PROGRAM +=head2 EXAMPLE PROGRAM + // a single header file is required #include + // every watcher type has its own typedef'd struct + // with the name ev_ ev_io stdin_watcher; ev_timer timeout_watcher; - /* called when data readable on stdin */ + // all watcher callbacks have a similar signature + // this callback is called when data is readable on stdin static void stdin_cb (EV_P_ struct ev_io *w, int revents) { - /* puts ("stdin ready"); */ - ev_io_stop (EV_A_ w); /* just a syntax example */ - ev_unloop (EV_A_ EVUNLOOP_ALL); /* leave all loop calls */ + 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_loop's to stop iterating + ev_unloop (EV_A_ EVUNLOOP_ALL); } + // another callback, this time for a time-out static void timeout_cb (EV_P_ struct ev_timer *w, int revents) { - /* puts ("timeout"); */ - ev_unloop (EV_A_ EVUNLOOP_ONE); /* leave one loop call */ + puts ("timeout"); + // this causes the innermost ev_loop to stop iterating + ev_unloop (EV_A_ EVUNLOOP_ONE); } int main (void) { + // use the default event loop unless you have special needs struct ev_loop *loop = ev_default_loop (0); - /* initialise an io watcher, then start it */ + // 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); - /* simple non-repeating 5.5 second timeout */ + // 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); - /* loop till timeout or data ready */ + // now wait for events to arrive ev_loop (loop, 0); + // unloop was called, so exit return 0; } =head1 DESCRIPTION -The newest version of this document is also available as a html-formatted +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. @@ -67,7 +81,7 @@ details of the event, and then hand it over to libev by I the watcher. -=head1 FEATURES +=head2 FEATURES Libev supports C. +=item EV_USE_EVENTFD + +If defined to be C<1>, then libev will assume that C is +available and will probe for kernel support at runtime. This will improve +C and C performance and reduce resource consumption. +If undefined, it will be enabled if the headers indicate GNU/Linux + Glibc +2.7 or newer, otherwise disabled. + =item EV_USE_SELECT If undefined or defined to be C<1>, libev will compile in support for the @@ -2360,6 +2821,14 @@ it is assumed that all these functions actually work on fds, even on win32. Should not be defined on non-win32 platforms. +=item EV_FD_TO_WIN32_HANDLE + +If C is enabled, then libev needs a way to map +file descriptors to socket handles. When not defining this symbol (the +default), then libev will call C<_get_osfhandle>, which is usually +correct. In some cases, programs use their own file descriptor management, +in which case they can provide this function to map fds to socket handles. + =item EV_USE_POLL If defined to be C<1>, libev will compile in support for the C(2) @@ -2370,8 +2839,9 @@ If defined to be C<1>, libev will compile in support for the Linux C(7) backend. Its availability will be detected at runtime, -otherwise another method will be used as fallback. This is the -preferred backend for GNU/Linux systems. +otherwise another method will be used as fallback. This is the preferred +backend for GNU/Linux systems. If undefined, it will be enabled if the +headers indicate GNU/Linux + Glibc 2.4 or newer, otherwise disabled. =item EV_USE_KQUEUE @@ -2400,13 +2870,25 @@ If defined to be C<1>, libev will compile in support for the Linux inotify interface to speed up C watchers. Its actual availability will -be detected at runtime. +be detected at runtime. If undefined, it will be enabled if the headers +indicate GNU/Linux + Glibc 2.4 or newer, otherwise disabled. + +=item EV_ATOMIC_T + +Libev requires an integer type (suitable for storing C<0> or C<1>) whose +access is atomic with respect to other threads or signal contexts. No such +type is easily found in the C language, so you can provide your own type +that you know is safe for your purposes. It is used both for signal handler "locking" +as well as for signal and thread safety in C watchers. + +In the absense of this define, libev will use C +(from F), which is usually good enough on most platforms. =item EV_H The name of the F header file used to include it. The default if -undefined is C<< >> in F and C<"ev.h"> in F. This -can be used to virtually rename the F header file in case of conflicts. +undefined is C<"ev.h"> in F, F and F. This can be +used to virtually rename the F header file in case of conflicts. =item EV_CONFIG_H @@ -2417,7 +2899,7 @@ =item EV_EVENT_H Similarly to C, this macro can be used to override F's idea -of how the F header can be found. +of how the F header can be found, the default is C<"event.h">. =item EV_PROTOTYPES @@ -2478,6 +2960,11 @@ If undefined or defined to be C<1>, then fork watchers are supported. If defined to be C<0>, then they are not. +=item EV_ASYNC_ENABLE + +If undefined or defined to be C<1>, then async watchers are supported. If +defined to be C<0>, then they are not. + =item EV_MINIMAL If you need to shave off some kilobytes of code at the expense of some @@ -2493,7 +2980,7 @@ =item EV_INOTIFY_HASHSIZE -C watchers use a small hash table to distribute workload by +C watchers use a small hash table to distribute workload by inotify watch id. The default size is C<16> (or C<1> with C), usually more than enough. If you need to manage thousands of C watchers you might want to increase this value (I be a power of @@ -2581,6 +3068,63 @@ #include "ev.c" +=head1 THREADS AND COROUTINES + +=head2 THREADS + +Libev itself is completely threadsafe, but it uses no locking. This +means that you can use as many loops as you want in parallel, as long as +only one thread ever calls into one libev function with the same loop +parameter. + +Or put differently: calls with different loop parameters can be done in +parallel from multiple threads, calls with the same loop parameter must be +done serially (but can be done from different threads, as long as only one +thread ever is inside a call at any point in time, e.g. by using a mutex +per loop). + +If you want to know which design is best for your problem, then I cannot +help you but by giving some generic advice: + +=over 4 + +=item * most applications have a main thread: use the default libev loop +in that thread, or create a seperate thread running only the default loop. + +This helps integrating other libraries or software modules that use libev +themselves and don't care/know about threading. + +=item * one loop per thread is usually a good model. + +Doing this is almost never wrong, sometimes a better-performance model +exists, but it is always a good start. + +=item * other models exist, such as the leader/follower pattern, where one +loop is handed through multiple threads in a kind of round-robbin fashion. + +Chosing a model is hard - look around, learn, know that usually you cna do +better than you currently do :-) + +=item * often you need to talk to some other thread which blocks in the +event loop - C watchers can be used to wake them up from other +threads safely (or from signal contexts...). + +=back + +=head2 COROUTINES + +Libev is much more accomodating to coroutines ("cooperative threads"): +libev fully supports nesting calls to it's functions from different +coroutines (e.g. you can call C on the same loop from two +different coroutines and switch freely between both coroutines running the +loop, as long as you don't confuse yourself). The only exception is that +you must not do this from C reschedule callbacks. + +Care has been invested into making sure that libev does not keep local +state inside C, and other calls do not usually allow coroutine +switches. + + =head1 COMPLEXITIES In this section the complexities of (many of) the algorithms used inside @@ -2599,17 +3143,18 @@ This means that, when you have a watcher that triggers in one hour and there are 100 watchers that would trigger before that then inserting will -have to skip those 100 watchers. +have to skip roughly seven (C) of these watchers. -=item Changing timer/periodic watchers (by autorepeat, again): O(log skipped_other_timers) +=item Changing timer/periodic watchers (by autorepeat or calling again): O(log skipped_other_timers) -That means that for changing a timer costs less than removing/adding them +That means that changing a timer costs less than removing/adding them as only the relative motion in the event queue has to be paid for. -=item Starting io/check/prepare/idle/signal/child watchers: O(1) +=item Starting io/check/prepare/idle/signal/child/fork/async watchers: O(1) These just add the watcher into an array or at the head of a list. -=item Stopping check/prepare/idle watchers: O(1) + +=item Stopping check/prepare/idle/fork/async watchers: O(1) =item Stopping an io/signal/child watcher: O(number_of_watchers_for_this_(fd/signal/pid % EV_PID_HASHSIZE)) @@ -2617,24 +3162,138 @@ correct watcher to remove. The lists are usually short (you don't usually have many watchers waiting for the same fd or signal). -=item Finding the next timer per loop iteration: O(1) +=item Finding the next timer in each loop iteration: O(1) + +By virtue of using a binary heap, the next timer is always found at the +beginning of the storage array. =item Each change on a file descriptor per loop iteration: O(number_of_watchers_for_this_fd) A change means an I/O watcher gets started or stopped, which requires -libev to recalculate its status (and possibly tell the kernel). +libev to recalculate its status (and possibly tell the kernel, depending +on backend and wether C was used). -=item Activating one watcher: O(1) +=item Activating one watcher (putting it into the pending state): O(1) =item Priority handling: O(number_of_priorities) Priorities are implemented by allocating some space for each priority. When doing priority-based operations, libev usually has to -linearly search all the priorities. +linearly search all the priorities, but starting/stopping and activating +watchers becomes O(1) w.r.t. priority handling. + +=item Sending an ev_async: O(1) + +=item Processing ev_async_send: O(number_of_async_watchers) + +=item Processing signals: O(max_signal_number) + +Sending involves a syscall I there were no other C +calls in the current loop iteration. Checking for async and signal events +involves iterating over all running async watchers or all signal numbers. =back +=head1 Win32 platform limitations and workarounds + +Win32 doesn't support any of the standards (e.g. POSIX) that libev +requires, and its I/O model is fundamentally incompatible with the POSIX +model. Libev still offers limited functionality on this platform in +the form of the C backend, and only supports socket +descriptors. This only applies when using Win32 natively, not when using +e.g. cygwin. + +There is no supported compilation method available on windows except +embedding it into other applications. + +Due to the many, low, and arbitrary limits on the win32 platform and the +abysmal performance of winsockets, using a large number of sockets is not +recommended (and not reasonable). If your program needs to use more than +a hundred or so sockets, then likely it needs to use a totally different +implementation for windows, as libev offers the POSIX model, which cannot +be implemented efficiently on windows (microsoft monopoly games). + +=over 4 + +=item The winsocket select function + +The winsocket C