--- EV-Loop-Async/Async.pm 2009/07/14 02:59:55 1.1 +++ EV-Loop-Async/Async.pm 2010/11/01 22:28:41 1.9 @@ -4,11 +4,76 @@ =head1 SYNOPSIS - use EV::Loop::Async; + use EV::Loop::Async; + + my $loop = EV::Loop::Async::default; + my $timer; + my $flag; + + # create a watcher, but make sure the loop is locked + { + $loop->scope_lock; # lock the loop structures + $timer = $loop->timer (5, 1, sub { $flag = 1 }); + $loop->notify; # tell loop to take note of the timer + } + + 1 while $flag; # $flag will be set asynchronously + + # implement a critical section, uninterrupted by any callbacks + { + $loop->interrupt->scope_block; + # critical section, no watcher callback interruptions + } + + # stop the timer watcher again - locking is required once more + { + $loop->scope_lock; # lock the loop structures + $timer->stop; + # no need to notify + } =head1 DESCRIPTION -TODO. +This module implements a rather specialised event loop - it takes a normal +L event loop and runs it in a separate thread. That means it will poll +for events even while your foreground Perl interpreter is busy (you don't +need to have perls pseudo-threads enabled for this either). + +Whenever the event loop detecs new events, it will interrupt perl and ask +it to invoke all the pending watcher callbacks. This invocation will be +"synchronous" (in the perl thread), but it can happen at any time. + +See the documentation for L for details on when and how +your perl program can be interrupted (and how to avoid it), and how to +integrate background event loops into foreground ones. + +=head1 FAQ + +=over 4 + +=item Why on earth...??? + +Sometimes you need lower latency for specific events, but it's too heavy +to continuously poll for events. And perl already does this for you +anyways, so this module only uses this existing mechanism. + +=item When do I have to lock? + +When in doubt, lock. Do not start or stop a watcher, do not create a +watcher (unless with the C<_ns> methods) and do not DESTROY an active +watcher without locking either. + +Any other event loop modifications need to be done while locked as +well. So when in doubt, lock (best using C). + +=item Why explicit locking? + +Because I was too lazy to wrap everything and there are probably only a +few people on this world using this module. + +=back + +=head1 FUNCTIONS, METHODS AND VARIABLES OF THIS MODULE =over 4 @@ -24,7 +89,7 @@ use base 'EV::Loop'; BEGIN { - our $VERSION = '0.02'; + our $VERSION = '1.01'; require XSLoader; XSLoader::load ("EV::Loop::Async", $VERSION); @@ -36,21 +101,49 @@ created on the first call to C by calling X, and should be used by all programs unless they have special requirements. +The associated L object is stored in +C<$EV::Loop::Async::AI>, and can be used to lock critical sections etc. + =cut -our ($LOOP, $ASYNC); +our ($LOOP, $INTERRUPT); sub default() { $LOOP || do { - $LOOP = new EV::Loop::Async; -# $ASYNC = $LOOP->async; + $LOOP = new EV::Loop::Async; + $INTERRUPT = $LOOP->interrupt; $LOOP } } +=item $EV::Loop::Async::LOOP + +The default async loop, available after the first call to +C. + +=item $EV::Loop::Async::INTERRUPT + +The default loop's L object, for easy access. + +Example: create a section of code where no callback invocations will +interrupt: + + { + $EV::Loop::Async::INTERRUPT->scope_block; + # no default loop callbacks will be executed here. + # the loop will not be locked, however. + } + +Example: embed the default EV::Async::Loop loop into the default L +loop (note that it could be any other event loop as well). -=item $loop = new EV::Loop $flags, [Async-Interrupt-Arguments...] + my $async_w = EV::io + $EV::Loop::Async::LOOP->interrupt->pipe_fileno, + EV::READ, + sub { }; + +=item $loop = new EV::Loop::Async $flags, [Async-Interrupt-Arguments...] This constructor: @@ -60,14 +153,33 @@ =item 2. creates a new L object and attaches itself to it. -=item 3. locks the loop (see below). - -=item 4. creates a new background thread. +=item 3. creates a new background thread. -=item 5. runs C<< $loop->run >> in that thread. +=item 4. runs C<< $loop->run >> in that thread. =back +The resulting loop will be running and unlocked when it is returned. + +Example: create a new loop, block it's interrupt object and embed +it into the foreground L event loop. This basically runs the +C loop in a synchronous way inside another loop. + + my $loop = new EV::Loop::Async 0; + my $async = $loop->interrupt; + + $async->block; + + my $async_w = AnyEvent->io ( + fh => $async->pipe_fileno, + poll => "r", + cb => sub { + # temporarily unblock to handle events + $async->unblock; + $async->block; + }, + ); + =cut sub new { @@ -76,12 +188,12 @@ my $self = bless $class->SUPER::new ($flags), $class; my ($c_func, $c_arg) = _c_func $self; my $asy = new Async::Interrupt @asy, c_cb => [$c_func, $c_arg]; - $self->_attach ($asy, $asy->signal_func); + _attach $self, $asy, $asy->signal_func; $self } -=item $loop->nudge +=item $loop->notify Wake up the asynchronous loop. This is useful after registering a new watcher, to ensure that the background event loop integrates the new @@ -89,7 +201,7 @@ calling this method). Without calling this method, the event loop I takes notice -of new watchers, bit when this happens is not wlel-defined (can be +of new watchers, bit when this happens is not well-defined (can be instantaneous, or take a few hours). No locking is required. @@ -103,11 +215,63 @@ { $loop->scope_lock; $timer = $loop->timer (1, 0, sub { $flag = 1 }); - $loop->nudge; + $loop->notify; } 1 until $flag; +=item $loop->lock + +=item $loop->unlock + +Lock/unlock the loop data structures. Since the event loop runs in +a separate thread, you have to lock the loop data structures before +accessing them in any way. Since I was lazy, you have to do this manually. + +You must lock under the same conditions as you would have to lock the +underlying C library, e.g. when starting or stopping watchers (but not +when creating or destroying them, but note that create and destroy often +starts and stops for you, in which case you have to lock). + +When in doubt, lock. + +See also the next method, C<< $loop->scope_lock >> for a more failsafe way +to lock parts of your code. + +Note that there must be exactly one call of "unblock" for every previous +call to "block" (i.e. calls can nest). + +=item $loop->scope_lock + +Calls C immediately, and C automatically whent he current +scope is left. + +=item $loop->set_max_foreground_loops ($max_loops) + +The background loop will immediately stop polling for new events after it +has collected at least one new event, regardless of how long it then takes +to actually handle them. + +When Perl finally handles the events, there could be many more ready +file descriptors. To improve latency and performance, you can ask +C to loop an additional number of times in the foreground +after invoking the callbacks, effectively doing the polling in the +foreground. + +The default is C<0>, meaning that no foreground polling will be done. A +value of C<1> means that, after handling the pending events, it will call +C<< $loop->loop (EV::LOOP_NONBLOCK) >> and handle the resulting events, if +any. A value of C<2> means that this will be iterated twice. + +When a foreground event poll does not yield any new events, then no +further iterations will be made, so this is only a I value of +additional loop runs. + +Take also note of the standard EV C +functionality, which can achieve a similar, but different, effect - YMMV. + +=back + =head1 SEE ALSO L, L.