--- libev/ev.pod 2007/12/22 06:16:36 1.99 +++ libev/ev.pod 2008/08/07 19:24:56 1.173 @@ -4,55 +4,69 @@ =head1 SYNOPSIS - #include + #include -=head1 EXAMPLE PROGRAM +=head2 EXAMPLE PROGRAM - #include + // a single header file is required + #include - ev_io stdin_watcher; - ev_timer timeout_watcher; + // 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 */ - 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 */ - } - - static void - timeout_cb (EV_P_ struct ev_timer *w, int revents) - { - /* puts ("timeout"); */ - ev_unloop (EV_A_ EVUNLOOP_ONE); /* leave one loop call */ - } - - int - main (void) - { - struct ev_loop *loop = ev_default_loop (0); - - /* initialise an io watcher, then start it */ - 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 */ - ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); - ev_timer_start (loop, &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_ struct 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_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"); + // 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 + // 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); - /* loop till timeout or data ready */ - ev_loop (loop, 0); + // now wait for events to arrive + ev_loop (loop, 0); - return 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. +time: L. 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 @@ -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 -C(2) backend. No attempt at auto-detection will be done: if no other method takes over, select will be it. Otherwise the select backend will not be compiled in. @@ -2357,7 +2893,7 @@ If defined to C<1>, then the select backend will use the system C structure. This is useful if libev doesn't compile due to a missing -C or C definition or it misguesses the bitset layout on +C or C definition or it mis-guesses the bitset layout on exotic systems. This usually limits the range of file descriptors to some low limit such as 1024 or might have other limitations (winsocket only allows 64 sockets). The C macro, set before compilation, might @@ -2373,6 +2909,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) @@ -2383,8 +2927,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 @@ -2407,19 +2952,31 @@ =item EV_USE_DEVPOLL -reserved for future expansion, works like the USE symbols above. +Reserved for future expansion, works like the USE symbols above. =item EV_USE_INOTIFY 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 absence 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 @@ -2430,7 +2987,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 @@ -2461,8 +3018,8 @@ and time, so using the defaults of five priorities (-2 .. +2) is usually fine. -If your embedding app does not need any priorities, defining these both to -C<0> will save some memory and cpu. +If your embedding application does not need any priorities, defining these both to +C<0> will save some memory and CPU. =item EV_PERIODIC_ENABLE @@ -2491,11 +3048,17 @@ 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 -speed, define this symbol to C<1>. Currently only used for gcc to override -some inlining decisions, saves roughly 30% codesize of amd64. +speed, define this symbol to C<1>. Currently this is used to override some +inlining decisions, saves roughly 30% code size on amd64. It also selects a +much smaller 2-heap for timer management over the default 4-heap. =item EV_PID_HASHSIZE @@ -2506,12 +3069,47 @@ =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 two). +=item EV_USE_4HEAP + +Heaps are not very cache-efficient. To improve the cache-efficiency of the +timer and periodics heap, libev uses a 4-heap when this symbol is defined +to C<1>. The 4-heap uses more complicated (longer) code but has +noticeably faster performance with many (thousands) of watchers. + +The default is C<1> unless C is set in which case it is C<0> +(disabled). + +=item EV_HEAP_CACHE_AT + +Heaps are not very cache-efficient. To improve the cache-efficiency of the +timer and periodics heap, libev can cache the timestamp (I) within +the heap structure (selected by defining C to C<1>), +which uses 8-12 bytes more per watcher and a few hundred bytes more code, +but avoids random read accesses on heap changes. This improves performance +noticeably with with many (hundreds) of watchers. + +The default is C<1> unless C is set in which case it is C<0> +(disabled). + +=item EV_VERIFY + +Controls how much internal verification (see C) will +be done: If set to C<0>, no internal verification code will be compiled +in. If set to C<1>, then verification code will be compiled in, but not +called. If set to C<2>, then the internal verification code will be +called once per loop, which can slow down libev. If set to C<3>, then the +verification code will be called very frequently, which will slow down +libev considerably. + +The default is C<1>, unless C is set, in which case it will be +C<0.> + =item EV_COMMON By default, all watchers have a C member. By redefining @@ -2521,9 +3119,9 @@ For example, the perl EV module uses something like this: - #define EV_COMMON \ - SV *self; /* contains this struct */ \ - SV *cb_sv, *fh /* note no trailing ";" */ + #define EV_COMMON \ + SV *self; /* contains this struct */ \ + SV *cb_sv, *fh /* note no trailing ";" */ =item EV_CB_DECLARE (type) @@ -2540,16 +3138,16 @@ =head2 EXPORTED API SYMBOLS -If you need to re-export the API (e.g. via a dll) and you need a list of +If you need to re-export the API (e.g. via a DLL) and you need a list of exported symbols, you can use the provided F files which list all public symbols, one per line: - Symbols.ev for libev proper - Symbols.event for the libevent emulation + Symbols.ev for libev proper + Symbols.event for the libevent emulation This can also be used to rename all public symbols to avoid clashes with multiple versions of libev linked together (which is obviously bad in -itself, but sometimes it is inconvinient to avoid this). +itself, but sometimes it is inconvenient to avoid this). A sed command like this will create wrapper C<#define>'s that you need to include before including F: @@ -2576,22 +3174,80 @@ The usage in rxvt-unicode is simpler. It has a F header file that everybody includes and which overrides some configure choices: - #define EV_MINIMAL 1 - #define EV_USE_POLL 0 - #define EV_MULTIPLICITY 0 - #define EV_PERIODIC_ENABLE 0 - #define EV_STAT_ENABLE 0 - #define EV_FORK_ENABLE 0 - #define EV_CONFIG_H - #define EV_MINPRI 0 - #define EV_MAXPRI 0 + #define EV_MINIMAL 1 + #define EV_USE_POLL 0 + #define EV_MULTIPLICITY 0 + #define EV_PERIODIC_ENABLE 0 + #define EV_STAT_ENABLE 0 + #define EV_FORK_ENABLE 0 + #define EV_CONFIG_H + #define EV_MINPRI 0 + #define EV_MAXPRI 0 - #include "ev++.h" + #include "ev++.h" And a F implementation file that contains libev proper and is compiled: - #include "ev_cpp.h" - #include "ev.c" + #include "ev_cpp.h" + #include "ev.c" + + +=head1 THREADS AND COROUTINES + +=head2 THREADS + +Libev itself is completely thread-safe, 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 (one loop, locking, or multiple loops +without or something else still) is best for your problem, then I cannot +help you. I can give some generic advice however: + +=over 4 + +=item * most applications have a main thread: use the default libev loop +in that thread, or create a separate 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-robin fashion. + +Choosing a model is hard - look around, learn, know that usually you can 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 accommodating 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 @@ -2612,17 +3268,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)) @@ -2630,24 +3287,245 @@ 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 or 4-heap, the next timer is always found at a +fixed position in 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 whether 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 system call 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. + +Lifting these limitations would basically require the full +re-implementation of the I/O system. If you are into these kinds of +things, then note that glib does exactly that for you in a very portable +way (note also that glib is the slowest event library known to man). + +There is no supported compilation method available on windows except +embedding it into other applications. + +Not a libev limitation but worth mentioning: windows apparently doesn't +accept large writes: instead of resulting in a partial write, windows will +either accept everything or return C if the buffer is too large, +so make sure you only write small amounts into your sockets (less than a +megabyte seems safe, but thsi apparently depends on the amount of memory +available). + +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 readiness +notification model, which cannot be implemented efficiently on windows +(Microsoft monopoly games). + +A typical way to use libev under windows is to embed it (see the embedding +section for details) and use the following F header file instead +of F: + + #define EV_STANDALONE /* keeps ev from requiring config.h */ + #define EV_SELECT_IS_WINSOCKET 1 /* configure libev for windows select */ + + #include "ev.h" + +And compile the following F file into your project (make sure +you do I compile the F or any other embedded soruce files!): + + #include "evwrap.h" + #include "ev.c" + +=over 4 + +=item The winsocket select function + +The winsocket C