--- libev/ev.pod 2010/10/24 20:05:43 1.327 +++ libev/ev.pod 2011/01/23 18:53:06 1.361 @@ -80,6 +80,14 @@ 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 @@ -235,7 +243,7 @@ See the description of C watchers for more info. -=item ev_set_allocator (void *(*cb)(void *ptr, long size)) [NOT REENTRANT] +=item ev_set_allocator (void *(*cb)(void *ptr, long size)) Sets the allocation function to use (the prototype is similar - the semantics are identical to the C C89/SuS/POSIX function). It is @@ -271,7 +279,7 @@ ... ev_set_allocator (persistent_realloc); -=item ev_set_syserr_cb (void (*cb)(const char *msg)); [NOT REENTRANT] +=item ev_set_syserr_cb (void (*cb)(const char *msg)) Set the callback function to call on a retryable system call error (such as failed select, poll, epoll_wait). The message is a printable string @@ -293,6 +301,19 @@ ... ev_set_syserr_cb (fatal_error); +=item ev_feed_signal (int signum) + +This function can be used to "simulate" a signal receive. It is completely +safe to call this function at any time, from any context, including signal +handlers or random threads. + +Its main use is to customise signal handling in your process, especially +in the presence of threads. For example, you could block signals +by default in all threads (and specifying C when +creating any loops), and in one thread, use C or any other +mechanism to wait for signals, then "deliver" them to libev by calling +C. + =back =head1 FUNCTIONS CONTROLLING EVENT LOOPS @@ -302,8 +323,8 @@ libev 3 had an C function colliding with the struct name). The library knows two types of such loops, the I loop, which -supports signals and child events, and dynamically created event loops -which do not. +supports child process events, and dynamically created event loops which +do not. =over 4 @@ -349,9 +370,9 @@ This will create and initialise a new event loop object. If the loop could not be initialised, returns false. -Note that this function I thread-safe, and one common way to use -libev with threads is indeed to create one loop per thread, and using the -default loop in the "main" or "initial" thread. +This function is thread-safe, and one common way to use libev with +threads is indeed to create one loop per thread, and using the default +loop in the "main" or "initial" thread. The flags argument can be used to specify special behaviour or specific backends to use, and is usually specified as C<0> (or C). @@ -396,14 +417,14 @@ =item C When this flag is specified, then libev will not attempt to use the -I API for it's C watchers. Apart from debugging and +I API for its C watchers. Apart from debugging and testing, this flag can be useful to conserve inotify file descriptors, as otherwise each loop using C watchers consumes one inotify handle. =item C When this flag is specified, then libev will attempt to use the -I API for it's C (and C) watchers. This API +I API for its C (and C) watchers. This API delivers signals synchronously, which makes it both faster and might make it possible to get the queued signal data. It can also simplify signal handling with threads, as long as you properly block signals in your @@ -413,6 +434,21 @@ there are a lot of shoddy libraries and programs (glib's threadpool for example) that can't properly initialise their signal masks. +=item C + +When this flag is specified, then libev will avoid to modify the signal +mask. Specifically, this means you ahve to make sure signals are unblocked +when you want to receive them. + +This behaviour is useful when you want to do your own signal handling, or +want to handle signals only in specific threads and want to avoid libev +unblocking the signals. + +It's also required by POSIX in a threaded program, as libev calls +C, whose behaviour is officially unspecified. + +This flag's behaviour will become the default in future versions of libev. + =item C (value 1, portable select backend) This is your standard select(2) backend. Not I standard, as @@ -457,11 +493,13 @@ The epoll mechanism deserves honorable mention as the most misdesigned of the more advanced event mechanisms: mere annoyances include silently dropping file descriptors, requiring a system call per change per file -descriptor (and unnecessary guessing of parameters), problems with dup and -so on. The biggest issue is fork races, however - if a program forks then -I parent and child process have to recreate the epoll set, which can -take considerable time (one syscall per file descriptor) and is of course -hard to detect. +descriptor (and unnecessary guessing of parameters), problems with dup, +returning before the timeout value, resulting in additional iterations +(and only giving 5ms accuracy while select on the same platform gives +0.1ms) and so on. The biggest issue is fork races, however - if a program +forks then I parent and child process have to recreate the epoll +set, which can take considerable time (one syscall per file descriptor) +and is of course hard to detect. Epoll is also notoriously buggy - embedding epoll fds I work, but of course I, and epoll just loves to report events for totally @@ -473,6 +511,10 @@ not least, it also refuses to work with some file descriptors which work perfectly fine with 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. +it in the child if you want to continue to use it in the child. -To support fork in your programs, you either have to call -C or C after a fork in the child, -enable C, or resort to C or -C. +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 @@ -2251,7 +2279,7 @@ Signal watchers will trigger an event when the process receives a specific signal one or more times. Even though signals are very asynchronous, libev -will try it's best to deliver signals synchronously, i.e. as part of the +will try its best to deliver signals synchronously, i.e. as part of the normal event processing, like any other event. If you want signals to be delivered truly asynchronously, just use @@ -2280,7 +2308,8 @@ Both the signal mask (C) and the signal disposition (C) are unspecified after starting a signal watcher (and after stopping it again), that is, libev might or might not block the signal, -and might or might not set or restore the installed signal handler. +and might or might not set or restore the installed signal handler (but +see C). While this does not matter for the signal disposition (libev never sets signals to C, so handlers will be reset to C on @@ -2304,6 +2333,20 @@ you expect it to be empty, you have a race condition in your code>. This is not a libev-specific thing, this is true for most event libraries. +=head3 The special problem of threads signal handling + +POSIX threads has problematic signal handling semantics, specifically, +a lot of functionality (sigfd, sigwait etc.) only really works if all +threads in a process block signals, which is hard to achieve. + +When you want to use sigwait (or mix libev signal handling with your own +for the same signals), you can tackle this problem by globally blocking +all signals before creating any threads (or creating them with a fully set +sigprocmask) and also specifying the C when creating +loops. Then designate one thread as "signal receiver thread" which handles +these signals. You can pass on any signals that libev might be interested +in by calling C. + =head3 Watcher-Specific Functions and Data Members =over 4 @@ -3100,15 +3143,15 @@ Initialises and configures the fork watcher - it has no parameters of any kind. There is a C macro, but using it is utterly pointless, -believe me. +really. =back =head2 C - even the best things end -Cleanup watchers are called just before the event loop they are registered -with is being destroyed. +Cleanup watchers are called just before the event loop is being destroyed +by a call to C. While there is no guarantee that the event loop gets destroyed, cleanup watchers provide a convenient method to install cleanup hooks for your @@ -3128,7 +3171,7 @@ Initialises and configures the cleanup watcher - it has no parameters of any kind. There is a C macro, but using it is utterly -pointless, believe me. +pointless, I assure you. =back @@ -3159,7 +3202,10 @@ This functionality is very similar to C watchers, as signals, too, are asynchronous in nature, and signals, too, will be compressed (i.e. the number of callback invocations may be less than the number of -C calls). +C calls). In fact, you could use signal watchers as a kind +of "global async watchers" by using a watcher on an otherwise unused +signal, and C to signal this watcher from another thread, +even without knowing which loop owns the signal. Unlike C watchers, C works with any event loop, not just the default loop. @@ -3345,12 +3391,322 @@ =item ev_feed_signal_event (loop, int signum) -Feed an event as if the given signal occurred (C must be the default -loop!). +Feed an event as if the given signal occurred. See also C, +which is async-safe. =back +=head1 COMMON OR USEFUL IDIOMS (OR BOTH) + +This section explains some common idioms that are not immediately +obvious. Note that examples are sprinkled over the whole manual, and this +section only contains stuff that wouldn't fit anywhere else. + +=head2 ASSOCIATING CUSTOM DATA WITH A WATCHER + +Each watcher has, by default, a C member that you can read +or modify at any time: libev will completely ignore it. This can be used +to associate arbitrary data with your watcher. If you need more data and +don't want to allocate memory separately and store a pointer to it in that +data member, you can also "subclass" the watcher type and provide your own +data: + + struct my_io + { + ev_io io; + int otherfd; + void *somedata; + struct whatever *mostinteresting; + }; + + ... + struct my_io w; + ev_io_init (&w.io, my_cb, fd, EV_READ); + +And since your callback will be called with a pointer to the watcher, you +can cast it back to your own type: + + static void my_cb (struct ev_loop *loop, ev_io *w_, int revents) + { + struct my_io *w = (struct my_io *)w_; + ... + } + +More interesting and less C-conformant ways of casting your callback +function type instead have been omitted. + +=head2 BUILDING YOUR OWN COMPOSITE WATCHERS + +Another common scenario is to use some data structure with multiple +embedded watchers, in effect creating your own watcher that combines +multiple libev event sources into one "super-watcher": + + struct my_biggy + { + int some_data; + ev_timer t1; + ev_timer t2; + } + +In this case getting the pointer to C is a bit more +complicated: Either you store the address of your C struct in +the C member of the watcher (for woozies or C++ coders), or you need +to use some pointer arithmetic using C inside your watchers (for +real programmers): + + #include + + static void + t1_cb (EV_P_ ev_timer *w, int revents) + { + struct my_biggy big = (struct my_biggy *) + (((char *)w) - offsetof (struct my_biggy, t1)); + } + + static void + t2_cb (EV_P_ ev_timer *w, int revents) + { + struct my_biggy big = (struct my_biggy *) + (((char *)w) - offsetof (struct my_biggy, t2)); + } + +=head2 MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS + +Often (especially in GUI toolkits) there are places where you have +I interaction, which is most easily implemented by recursively +invoking C. + +This brings the problem of exiting - a callback might want to finish the +main C call, but not the nested one (e.g. user clicked "Quit", but +a modal "Are you sure?" dialog is still waiting), or just the nested one +and not the main one (e.g. user clocked "Ok" in a modal dialog), or some +other combination: In these cases, C will not work alone. + +The solution is to maintain "break this loop" variable for each C +invocation, and use a loop around C until the condition is +triggered, using C: + + // main loop + int exit_main_loop = 0; + + while (!exit_main_loop) + ev_run (EV_DEFAULT_ EVRUN_ONCE); + + // in a model watcher + int exit_nested_loop = 0; + + while (!exit_nested_loop) + ev_run (EV_A_ EVRUN_ONCE); + +To exit from any of these loops, just set the corresponding exit variable: + + // exit modal loop + exit_nested_loop = 1; + + // exit main program, after modal loop is finished + exit_main_loop = 1; + + // exit both + exit_main_loop = exit_nested_loop = 1; + +=head2 THREAD LOCKING EXAMPLE + +Here is a fictitious example of how to run an event loop in a different +thread from where callbacks are being invoked and watchers are +created/added/removed. + +For a real-world example, see the C perl module, +which uses exactly this technique (which is suited for many high-level +languages). + +The example uses a pthread mutex to protect the loop data, a condition +variable to wait for callback invocations, an async watcher to notify the +event loop thread and an unspecified mechanism to wake up the main thread. + +First, you need to associate some data with the event loop: + + typedef struct { + mutex_t lock; /* global loop lock */ + ev_async async_w; + thread_t tid; + cond_t invoke_cv; + } userdata; + + void prepare_loop (EV_P) + { + // for simplicity, we use a static userdata struct. + static userdata u; + + ev_async_init (&u->async_w, async_cb); + ev_async_start (EV_A_ &u->async_w); + + pthread_mutex_init (&u->lock, 0); + pthread_cond_init (&u->invoke_cv, 0); + + // now associate this with the loop + ev_set_userdata (EV_A_ u); + ev_set_invoke_pending_cb (EV_A_ l_invoke); + ev_set_loop_release_cb (EV_A_ l_release, l_acquire); + + // then create the thread running ev_loop + pthread_create (&u->tid, 0, l_run, EV_A); + } + +The callback for the C watcher does nothing: the watcher is used +solely to wake up the event loop so it takes notice of any new watchers +that might have been added: + + static void + async_cb (EV_P_ ev_async *w, int revents) + { + // just used for the side effects + } + +The C and C callbacks simply unlock/lock the mutex +protecting the loop data, respectively. + + static void + l_release (EV_P) + { + userdata *u = ev_userdata (EV_A); + pthread_mutex_unlock (&u->lock); + } + + static void + l_acquire (EV_P) + { + userdata *u = ev_userdata (EV_A); + pthread_mutex_lock (&u->lock); + } + +The event loop thread first acquires the mutex, and then jumps straight +into C: + + void * + l_run (void *thr_arg) + { + struct ev_loop *loop = (struct ev_loop *)thr_arg; + + l_acquire (EV_A); + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); + ev_run (EV_A_ 0); + l_release (EV_A); + + return 0; + } + +Instead of invoking all pending watchers, the C callback will +signal the main thread via some unspecified mechanism (signals? pipe +writes? C?) and then waits until all pending watchers +have been called (in a while loop because a) spurious wakeups are possible +and b) skipping inter-thread-communication when there are no pending +watchers is very beneficial): + + static void + l_invoke (EV_P) + { + userdata *u = ev_userdata (EV_A); + + while (ev_pending_count (EV_A)) + { + wake_up_other_thread_in_some_magic_or_not_so_magic_way (); + pthread_cond_wait (&u->invoke_cv, &u->lock); + } + } + +Now, whenever the main thread gets told to invoke pending watchers, it +will grab the lock, call C and then signal the loop +thread to continue: + + static void + real_invoke_pending (EV_P) + { + userdata *u = ev_userdata (EV_A); + + pthread_mutex_lock (&u->lock); + ev_invoke_pending (EV_A); + pthread_cond_signal (&u->invoke_cv); + pthread_mutex_unlock (&u->lock); + } + +Whenever you want to start/stop a watcher or do other modifications to an +event loop, you will now have to lock: + + ev_timer timeout_watcher; + userdata *u = ev_userdata (EV_A); + + ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); + + pthread_mutex_lock (&u->lock); + ev_timer_start (EV_A_ &timeout_watcher); + ev_async_send (EV_A_ &u->async_w); + pthread_mutex_unlock (&u->lock); + +Note that sending the C watcher is required because otherwise +an event loop currently blocking in the kernel will have no knowledge +about the newly added timer. By waking up the loop it will pick up any new +watchers in the next event loop iteration. + +=head2 THREADS, COROUTINES, CONTINUATIONS, QUEUES... INSTEAD OF CALLBACKS + +While the overhead of a callback that e.g. schedules a thread is small, it +is still an overhead. If you embed libev, and your main usage is with some +kind of threads or coroutines, you might want to customise libev so that +doesn't need callbacks anymore. + +Imagine you have coroutines that you can switch to using a function +C, that libev runs in a coroutine called C +and that due to some magic, the currently active coroutine is stored in a +global called C. Then you can build your own "wait for libev +event" primitive by changing C and C (note +the differing C<;> conventions): + + #define EV_CB_DECLARE(type) struct my_coro *cb; + #define EV_CB_INVOKE(watcher) switch_to ((watcher)->cb) + +That means instead of having a C callback function, you store the +coroutine to switch to in each watcher, and instead of having libev call +your callback, you instead have it switch to that coroutine. + +A coroutine might now wait for an event with a function called +C. (the watcher needs to be started, as always, but it doesn't +matter when, or whether the watcher is active or not when this function is +called): + + void + wait_for_event (ev_watcher *w) + { + ev_cb_set (w) = current_coro; + switch_to (libev_coro); + } + +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 :) + +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 +switching to a coroutine, you push the watcher onto the queue and notify +any waiters. + +To embed libev, see L, but in short, it's easiest to create two +files, F and F that include the respective libev files: + + // my_ev.h + #define EV_CB_DECLARE(type) struct my_coro *cb; + #define EV_CB_INVOKE(watcher) switch_to ((watcher)->cb); + #include "../libev/ev.h" + + // my_ev.c + #define EV_H "my_ev.h" + #include "../libev/ev.c" + +And then use F when you would normally use F, and compile +F into your project. When properly specifying include paths, you +can even use F as header file name directly. + + =head1 LIBEVENT EMULATION Libev offers a compatibility emulation layer for libevent. It cannot @@ -3358,6 +3714,11 @@ =over 4 +=item * Only the libevent-1.4.1-beta API is being emulated. + +This was the newest libevent version available when libev was implemented, +and is still mostly unchanged in 2010. + =item * Use it by including , as usual. =item * The following members are fully supported: ev_base, ev_callback, @@ -3372,7 +3733,7 @@ is an ev_pri field. =item * In libevent, the last base created gets the signals, in libev, the -first base created (== the default loop) gets the signals. +base that registered the signal gets the signals. =item * Other members are not supported. @@ -3401,11 +3762,11 @@ that the watcher is associated with (or no additional members at all if you disable C when embedding libev). -Currently, functions, and static and non-static member functions can be -used as callbacks. Other types should be easy to add as long as they only -need one additional pointer for context. If you need support for other -types of functors please contact the author (preferably after implementing -it). +Currently, functions, static and non-static member functions and classes +with C can be used as callbacks. Other types should be easy +to add as long as they only need one additional pointer for context. If +you need support for other types of functors please contact the author +(preferably after implementing it). Here is a list of things available in the C namespace: @@ -4283,7 +4644,7 @@ #include "ev_cpp.h" #include "ev.c" -=head1 INTERACTION WITH OTHER PROGRAMS OR LIBRARIES +=head1 INTERACTION WITH OTHER PROGRAMS, LIBRARIES OR THE ENVIRONMENT =head2 THREADS AND COROUTINES @@ -4344,143 +4705,7 @@ =back -=head4 THREAD LOCKING EXAMPLE - -Here is a fictitious example of how to run an event loop in a different -thread than where callbacks are being invoked and watchers are -created/added/removed. - -For a real-world example, see the C perl module, -which uses exactly this technique (which is suited for many high-level -languages). - -The example uses a pthread mutex to protect the loop data, a condition -variable to wait for callback invocations, an async watcher to notify the -event loop thread and an unspecified mechanism to wake up the main thread. - -First, you need to associate some data with the event loop: - - typedef struct { - mutex_t lock; /* global loop lock */ - ev_async async_w; - thread_t tid; - cond_t invoke_cv; - } userdata; - - void prepare_loop (EV_P) - { - // for simplicity, we use a static userdata struct. - static userdata u; - - ev_async_init (&u->async_w, async_cb); - ev_async_start (EV_A_ &u->async_w); - - pthread_mutex_init (&u->lock, 0); - pthread_cond_init (&u->invoke_cv, 0); - - // now associate this with the loop - ev_set_userdata (EV_A_ u); - ev_set_invoke_pending_cb (EV_A_ l_invoke); - ev_set_loop_release_cb (EV_A_ l_release, l_acquire); - - // then create the thread running ev_loop - pthread_create (&u->tid, 0, l_run, EV_A); - } - -The callback for the C watcher does nothing: the watcher is used -solely to wake up the event loop so it takes notice of any new watchers -that might have been added: - - static void - async_cb (EV_P_ ev_async *w, int revents) - { - // just used for the side effects - } - -The C and C callbacks simply unlock/lock the mutex -protecting the loop data, respectively. - - static void - l_release (EV_P) - { - userdata *u = ev_userdata (EV_A); - pthread_mutex_unlock (&u->lock); - } - - static void - l_acquire (EV_P) - { - userdata *u = ev_userdata (EV_A); - pthread_mutex_lock (&u->lock); - } - -The event loop thread first acquires the mutex, and then jumps straight -into C: - - void * - l_run (void *thr_arg) - { - struct ev_loop *loop = (struct ev_loop *)thr_arg; - - l_acquire (EV_A); - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); - ev_run (EV_A_ 0); - l_release (EV_A); - - return 0; - } - -Instead of invoking all pending watchers, the C callback will -signal the main thread via some unspecified mechanism (signals? pipe -writes? C?) and then waits until all pending watchers -have been called (in a while loop because a) spurious wakeups are possible -and b) skipping inter-thread-communication when there are no pending -watchers is very beneficial): - - static void - l_invoke (EV_P) - { - userdata *u = ev_userdata (EV_A); - - while (ev_pending_count (EV_A)) - { - wake_up_other_thread_in_some_magic_or_not_so_magic_way (); - pthread_cond_wait (&u->invoke_cv, &u->lock); - } - } - -Now, whenever the main thread gets told to invoke pending watchers, it -will grab the lock, call C and then signal the loop -thread to continue: - - static void - real_invoke_pending (EV_P) - { - userdata *u = ev_userdata (EV_A); - - pthread_mutex_lock (&u->lock); - ev_invoke_pending (EV_A); - pthread_cond_signal (&u->invoke_cv); - pthread_mutex_unlock (&u->lock); - } - -Whenever you want to start/stop a watcher or do other modifications to an -event loop, you will now have to lock: - - ev_timer timeout_watcher; - userdata *u = ev_userdata (EV_A); - - ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); - - pthread_mutex_lock (&u->lock); - ev_timer_start (EV_A_ &timeout_watcher); - ev_async_send (EV_A_ &u->async_w); - pthread_mutex_unlock (&u->lock); - -Note that sending the C watcher is required because otherwise -an event loop currently blocking in the kernel will have no knowledge -about the newly added timer. By waking up the loop it will pick up any new -watchers in the next event loop iteration. +See also L. =head3 COROUTINES @@ -4759,6 +4984,11 @@ callback: The watcher callbacks have different type signatures, but libev calls them using an C internally. +=item pointer accesses must be thread-atomic + +Accessing a pointer value must be atomic, it must both be readable and +writable in one piece - this is the case on all current architectures. + =item C must be thread-atomic as well The type C (or whatever is defined as @@ -4874,14 +5104,21 @@ =head1 PORTING FROM LIBEV 3.X TO 4.X -The major version 4 introduced some minor incompatible changes to the API. +The major version 4 introduced some incompatible changes to the API. -At the moment, the C header file tries to implement superficial -compatibility, so most programs should still compile. Those might be -removed in later versions of libev, so better update early than late. +At the moment, the C header file provides compatibility definitions +for all changes, so most programs should still compile. The compatibility +layer might be removed in later versions of libev, so better update to the +new API early than late. =over 4 +=item C backwards compatibility mechanism + +The backward compatibility mechanism can be controlled by +C. See L in the L +section. + =item C and C have been removed These calls can be replaced easily by their C counterparts: @@ -4916,12 +5153,6 @@ C because it would otherwise clash with the C typedef. -=item C backwards compatibility mechanism - -The backward compatibility mechanism can be controlled by -C. See L in the L -section. - =item C mechanism replaced by C The preprocessor symbol C has been replaced by a different @@ -5005,5 +5236,6 @@ =head1 AUTHOR -Marc Lehmann , with repeated corrections by Mikael Magnusson. +Marc Lehmann , with repeated corrections by Mikael +Magnusson and Emanuele Giaquinta.