--- libev/ev.pod 2008/01/10 06:00:55 1.118 +++ libev/ev.pod 2008/02/01 13:53:56 1.128 @@ -485,14 +485,16 @@ =item ev_default_fork () -This function reinitialises the kernel state for backends that have -one. Despite the name, you can call it anytime, but it makes most sense -after forking, in either the parent or child process (or both, but that -again makes little sense). - -You I call this function in the child process after forking if and -only if you want to use the event library in both processes. If you just -fork+exec, you don't have to call it. +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 (or both child and parent, but that again makes little +sense). You I call it in the child before using any of the libev +functions, and it will only take effect at the next C iteration. + +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 library in the child. If +you just fork+exec, you don't have to call it at all. The function itself is quite fast and it's usually not a problem to call it just in case after a fork. To make this easy, the function will fit in @@ -500,10 +502,6 @@ pthread_atfork (0, 0, ev_default_fork); -At the moment, C and C are safe to use -without calling this function, so if you force one of those backends you -do not need to care. - =item ev_loop_fork (loop) Like C, but acts on an event loop created by @@ -778,6 +776,10 @@ The event loop has been resumed in the child process after fork (see C). +=item C + +The given async watcher has been asynchronously notified (see C). + =item C An unspecified error has occured, the watcher has been stopped. This might @@ -1442,16 +1444,18 @@ =over 4 -=item ev_child_init (ev_child *, callback, int pid) +=item ev_child_init (ev_child *, callback, int pid, int trace) -=item ev_child_set (ev_child *, int pid) +=item ev_child_set (ev_child *, int pid, int trace) Configures the watcher to wait for status changes of process C (or I process if C is specified as C<0>). The callback can look at the C member of the C watcher structure to see the status word (use the macros from C and see your systems C documentation). The C member contains the pid of the -process causing the status change. +process causing the status change. C must be either C<0> (only +activate the watcher when the process terminates) or C<1> (additionally +activate the watcher when the process is stopped or continued). =item int pid [read-only] @@ -1697,7 +1701,7 @@ { free (w); // now do something you wanted to do when the program has - // no longer asnything immediate to do. + // no longer anything immediate to do. } struct ev_idle *idle_watcher = malloc (sizeof (struct ev_idle)); @@ -2048,6 +2052,136 @@ =back +=head2 C - how to wake up another event loop + +In general, you cannot use an C from multiple threads or other +asynchronous sources such as signal handlers (as opposed to multiple event +loops - those are of course safe to use in different threads). + +Sometimes, however, you need to wake up another event loop you do not +control, for example because it belongs to another thread. This is what +C watchers do: as long as the C watcher is active, you +can signal it by calling C, which is thread- and signal +safe. + +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). + +Unlike C watchers, C works with any event loop, not +just the default loop. + +=head3 Queueing + +C does not support queueing of data in any way. The reason +is that the author does not know of a simple (or any) algorithm for a +multiple-writer-single-reader queue that works in all cases and doesn't +need elaborate support such as pthreads. + +That means that if you want to queue data, you have to provide your own +queue. And here is how you would implement locking: + +=over 4 + +=item queueing from a signal handler context + +To implement race-free queueing, you simply add to the queue in the signal +handler but you block the signal handler in the watcher callback. Here is an example that does that for +some fictitiuous SIGUSR1 handler: + + static ev_async mysig; + + static void + sigusr1_handler (void) + { + sometype data; + + // no locking etc. + queue_put (data); + ev_async_send (DEFAULT_ &mysig); + } + + static void + mysig_cb (EV_P_ ev_async *w, int revents) + { + sometype data; + sigset_t block, prev; + + sigemptyset (&block); + sigaddset (&block, SIGUSR1); + sigprocmask (SIG_BLOCK, &block, &prev); + + while (queue_get (&data)) + process (data); + + if (sigismember (&prev, SIGUSR1) + sigprocmask (SIG_UNBLOCK, &block, 0); + } + +(Note: pthreads in theory requires you to use C +instead of C when you use threads, but libev doesn't do it +either...). + +=item queueing from a thread context + +The strategy for threads is different, as you cannot (easily) block +threads but you can easily preempt them, so to queue safely you need to +emply a traditional mutex lock, such as in this pthread example: + + static ev_async mysig; + static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; + + static void + otherthread (void) + { + // only need to lock the actual queueing operation + pthread_mutex_lock (&mymutex); + queue_put (data); + pthread_mutex_unlock (&mymutex); + + ev_async_send (DEFAULT_ &mysig); + } + + static void + mysig_cb (EV_P_ ev_async *w, int revents) + { + pthread_mutex_lock (&mymutex); + + while (queue_get (&data)) + process (data); + + pthread_mutex_unlock (&mymutex); + } + +=back + + +=head3 Watcher-Specific Functions and Data Members + +=over 4 + +=item ev_async_init (ev_async *, callback) + +Initialises and configures the async watcher - it has no parameters of any +kind. There is a C macro, but using it is utterly pointless, +believe me. + +=item ev_async_send (loop, ev_async *) + +Sends/signals/activates the given C watcher, that is, feeds +an C event on the watcher into the event loop. Unlike +C, this call is safe to do in other threads, signal or +similar contexts (see the dicusssion of C in the embedding +section below on what exactly this means). + +This call incurs the overhead of a syscall only once per loop iteration, +so while the overhead might be noticable, it doesn't apply to repeated +calls to C. + +=back + + =head1 OTHER FUNCTIONS There are some other functions of possible interest. Described. Here. Now. @@ -2284,19 +2418,17 @@ class myclass { - ev_io io; void io_cb (ev::io &w, int revents); - ev_idle idle void idle_cb (ev::idle &w, int revents); + ev::io io; void io_cb (ev::io &w, int revents); + ev:idle idle void idle_cb (ev::idle &w, int revents); - myclass (); - } - - myclass::myclass (int fd) - { - io .set (this); - idle.set (this); + myclass (int fd) + { + io .set (this); + idle.set (this); - io.start (fd, ev::READ); - } + io.start (fd, ev::READ); + } + }; =head1 MACRO MAGIC @@ -2562,6 +2694,17 @@ interface to speed up C watchers. Its actual availability will be detected at runtime. +=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 @@ -2638,6 +2781,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 @@ -2766,11 +2914,11 @@ 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)) @@ -2798,6 +2946,16 @@ linearly search all the priorities, but starting/stopping and activating watchers becomes O(1) w.r.t. prioritiy 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