--- AnyEvent/lib/AnyEvent.pm 2009/07/18 15:51:52 1.246 +++ AnyEvent/lib/AnyEvent.pm 2009/07/29 12:39:21 1.263 @@ -1,9 +1,9 @@ =head1 NAME -AnyEvent - provide framework for multiple event loops +AnyEvent - the DBI of event loop programming -EV, Event, Glib, Tk, Perl, Event::Lib, Qt and POE are various supported -event loops. +EV, Event, Glib, Tk, Perl, Event::Lib, Irssi, rxvt-unicode, IO::Async, Qt +and POE are various supported event loops/environments. =head1 SYNOPSIS @@ -43,6 +43,14 @@ in a tutorial or some gentle introduction, have a look at the L manpage. +=head1 SUPPORT + +There is a mailinglist for discussing all things AnyEvent, and an IRC +channel, too. + +See the AnyEvent project page at the B, at L, for more info. + =head1 WHY YOU SHOULD USE THIS MODULE (OR NOT) Glib, POE, IO::Async, Event... CPAN offers event models by the dozen @@ -370,8 +378,14 @@ so programs overwriting those signals directly will likely not work correctly. -Also note that many event loops (e.g. Glib, Tk, Qt, IO::Async) do not -support attaching callbacks to signals, which is a pity, as you cannot do +Example: exit on SIGINT + + my $w = AnyEvent->signal (signal => "INT", cb => sub { exit 1 }); + +=head3 Signal Races, Delays and Workarounds + +Many event loops (e.g. Glib, Tk, Qt, IO::Async) do not support attaching +callbacks to signals in a generic way, which is a pity, as you cannot do race-free signal handling in perl. AnyEvent will try to do it's best, but in some cases, signals will be delayed. The maximum time a signal might be delayed is specified in C<$AnyEvent::MAX_SIGNAL_LATENCY> (default: 10 @@ -379,20 +393,20 @@ watcher is created, and should be left alone otherwise. Higher values will cause fewer spurious wake-ups, which is better for power and CPU saving. All these problems can be avoided by installing the optional -L module. - -Example: exit on SIGINT - - my $w = AnyEvent->signal (signal => "INT", cb => sub { exit 1 }); +L module. This will not work with inherently broken +event loops such as L or L (and not with L +currently, as POE does it's own workaround with one-second latency). With +those, you just have to suffer the delays. =head2 CHILD PROCESS WATCHERS You can also watch on a child process exit and catch its exit status. -The child process is specified by the C argument (if set to C<0>, it -watches for any child process exit). The watcher will triggered only when -the child process has finished and an exit status is available, not on -any trace events (stopped/continued). +The child process is specified by the C argument (one some backends, +using C<0> watches for any child process exit, on others this will +croak). The watcher will be triggered only when the child process has +finished and an exit status is available, not on any trace events +(stopped/continued). The callback will be called with the pid and exit status (as returned by waitpid), so unlike other watcher types, you I rely on child watcher @@ -506,7 +520,8 @@ in time where multiple outstanding events have been processed. And yet another way to call them is transactions - each condition variable can be used to represent a transaction, which finishes at some point and delivers -a result. +a result. And yet some people know them as "futures" - a promise to +compute/deliver something that you can wait for. Condition variables are very useful to signal that something has finished, for example, if you write a module that does asynchronous http requests, @@ -784,6 +799,7 @@ AnyEvent::Impl::Tk based on Tk, very broken. AnyEvent::Impl::EventLib based on Event::Lib, leaks memory and worse. AnyEvent::Impl::POE based on POE, very slow, some limitations. + AnyEvent::Impl::Irssi used when running within irssi. =item Backends with special needs. @@ -867,8 +883,25 @@ avoid autodetecting the event module at load time. If called in scalar or list context, then it creates and returns an object -that automatically removes the callback again when it is destroyed. See -L for a case where this is useful. +that automatically removes the callback again when it is destroyed (or +C when the hook was immediately executed). See L for +a case where this is useful. + +Example: Create a watcher for the IO::AIO module and store it in +C<$WATCHER>. Only do so after the event loop is initialised, though. + + our WATCHER; + + my $guard = AnyEvent::post_detect { + $WATCHER = AnyEvent->io (fh => IO::AIO::poll_fileno, poll => 'r', cb => \&IO::AIO::poll_cb); + }; + + # the ||= is important in case post_detect immediately runs the block, + # as to not clobber the newly-created watcher. assigning both watcher and + # post_detect guard to the same variable has the advantage of users being + # able to just C if the watcher causes them grief. + + $WATCHER ||= $guard; =item @AnyEvent::post_detect @@ -1055,7 +1088,7 @@ use Carp (); -our $VERSION = 4.85; +our $VERSION = 4.881; our $MODEL; our $AUTOLOAD; @@ -1090,14 +1123,15 @@ } my @models = ( - [EV:: => AnyEvent::Impl::EV::], - [Event:: => AnyEvent::Impl::Event::], - [AnyEvent::Impl::Perl:: => AnyEvent::Impl::Perl::], - # everything below here will not be autoprobed + [EV:: => AnyEvent::Impl::EV:: , 1], + [Event:: => AnyEvent::Impl::Event::, 1], + [AnyEvent::Impl::Perl:: => AnyEvent::Impl::Perl:: , 1], + # everything below here will not (normally) be autoprobed # as the pureperl backend should work everywhere # and is usually faster - [Glib:: => AnyEvent::Impl::Glib::], # becomes extremely slow with many watchers + [Glib:: => AnyEvent::Impl::Glib:: , 1], # becomes extremely slow with many watchers [Event::Lib:: => AnyEvent::Impl::EventLib::], # too buggy + [Irssi:: => AnyEvent::Impl::Irssi::], # Irssi has a bogus "Event" package [Tk:: => AnyEvent::Impl::Tk::], # crashes with many handles [Qt:: => AnyEvent::Impl::Qt::], # requires special main program [POE::Kernel:: => AnyEvent::Impl::POE::], # lasciate ogni speranza @@ -1107,9 +1141,9 @@ # byzantine signal and broken child handling, among others. # IO::Async is rather hard to detect, as it doesn't have any # obvious default class. -# [IO::Async:: => AnyEvent::Impl::IOAsync::], # requires special main program -# [IO::Async::Loop:: => AnyEvent::Impl::IOAsync::], # requires special main program -# [IO::Async::Notifier:: => AnyEvent::Impl::IOAsync::], # requires special main program +# [0, IO::Async:: => AnyEvent::Impl::IOAsync::], # requires special main program +# [0, IO::Async::Loop:: => AnyEvent::Impl::IOAsync::], # requires special main program +# [0, IO::Async::Notifier:: => AnyEvent::Impl::IOAsync::], # requires special main program ); our %method = map +($_ => 1), @@ -1123,7 +1157,7 @@ if ($MODEL) { $cb->(); - 1 + undef } else { push @post_detect, $cb; @@ -1165,15 +1199,17 @@ } unless ($MODEL) { - # try to load a model - + # try to autoload a model for (@REGISTRY, @models) { - my ($package, $model) = @$_; - if (eval "require $package" - and ${"$package\::VERSION"} > 0 - and eval "require $model") { + my ($package, $model, $autoload) = @$_; + if ( + $autoload + and eval "require $package" + and ${"$package\::VERSION"} > 0 + and eval "require $model" + ) { $MODEL = $model; - warn "AnyEvent: autoprobed model '$model', using it.\n" if $VERBOSE >= 2; + warn "AnyEvent: autoloaded model '$model', using it.\n" if $VERBOSE >= 2; last; } } @@ -1255,6 +1291,15 @@ # default implementation for ->signal our $HAVE_ASYNC_INTERRUPT; + +sub _have_async_interrupt() { + $HAVE_ASYNC_INTERRUPT = 1*(!$ENV{PERL_ANYEVENT_AVOID_ASYNC_INTERRUPT} + && eval "use Async::Interrupt 1.0 (); 1") + unless defined $HAVE_ASYNC_INTERRUPT; + + $HAVE_ASYNC_INTERRUPT +} + our ($SIGPIPE_R, $SIGPIPE_W, %SIG_CB, %SIG_EV, $SIG_IO); our (%SIG_ASY, %SIG_ASY_W); our ($SIG_COUNT, $SIG_TW); @@ -1272,7 +1317,7 @@ } } -# install a dumym wakeupw atcher to reduce signal catching latency +# install a dummy wakeup watcher to reduce signal catching latency sub _sig_add() { unless ($SIG_COUNT++) { # try to align timer on a full-second boundary, if possible @@ -1291,31 +1336,59 @@ unless --$SIG_COUNT; } +our %SIGNAME2NUM; +our @SIGNUM2NAME; +our $_sig_name_init; $_sig_name_init = sub { + undef $_sig_name_init; + + if (_have_async_interrupt) { + *sig2num = \&Async::Interrupt::sig2num; + *sig2name = \&Async::Interrupt::sig2name; + } else { + require Config; + + @SIGNAME2NUM{ split ' ', $Config::Config{sig_name} } + = split ' ', $Config::Config{sig_num}; + @SIGNUM2NAME[values %SIGNAME2NUM] = keys %SIGNAME2NUM; + + *sig2num = sub($) { + $_[0] > 0 ? shift : $SIGNAME2NUM{+shift} + }; + *sig2name = sub ($) { + $_[0] > 0 ? $SIGNUM2NAME[+shift] : shift + }; + } +}; + +sub sig2num ($) { &$_sig_name_init; &sig2num } +sub sig2name($) { &$_sig_name_init; &sig2name } + sub _signal { my (undef, %arg) = @_; my $signal = uc $arg{signal} or Carp::croak "required option 'signal' is missing"; - $SIG_CB{$signal}{$arg{cb}} = $arg{cb}; - if ($HAVE_ASYNC_INTERRUPT) { # async::interrupt - $SIG_ASY{$signal} ||= do { - my $asy = new Async::Interrupt - cb => sub { undef $SIG_EV{$signal} }, - signal => $signal, - pipe => [$SIGPIPE_R->filenos], - ; - $asy->pipe_autodrain (0); + $signal = sig2num $signal; + $SIG_CB{$signal}{$arg{cb}} = $arg{cb}; - $asy - }; + $SIG_ASY{$signal} ||= new Async::Interrupt + cb => sub { undef $SIG_EV{$signal} }, + signal => $signal, + pipe => [$SIGPIPE_R->filenos], + pipe_autodrain => 0, + ; } else { # pure perl + # AE::Util has been loaded in signal + $signal = sig2name $signal; + $SIG_CB{$signal}{$arg{cb}} = $arg{cb}; + $SIG{$signal} ||= sub { local $!; syswrite $SIGPIPE_W, "\x00", 1 unless %SIG_EV; @@ -1332,10 +1405,9 @@ sub signal { # probe for availability of Async::Interrupt - if (!$ENV{PERL_ANYEVENT_AVOID_ASYNC_INTERRUPT} && eval "use Async::Interrupt 0.6 (); 1") { + if (_have_async_interrupt) { warn "AnyEvent: using Async::Interrupt for race-free signal handling.\n" if $VERBOSE >= 8; - $HAVE_ASYNC_INTERRUPT = 1; $SIGPIPE_R = new Async::Interrupt::EventPipe; $SIG_IO = AnyEvent->io (fh => $SIGPIPE_R->fileno, poll => "r", cb => \&_signal_exec); @@ -1393,12 +1465,19 @@ our $CHLD_DELAY_W; our $WNOHANG; +sub _emit_childstatus($$) { + my (undef, $rpid, $rstatus) = @_; + + $_->($rpid, $rstatus) + for values %{ $PID_CB{$rpid} || {} }, + values %{ $PID_CB{0} || {} }; +} + sub _sigchld { - while (0 < (my $pid = waitpid -1, $WNOHANG)) { - $_->($pid, $?) - for values %{ $PID_CB{$pid} || {} }, - values %{ $PID_CB{0} || {} }; - } + my $pid; + + AnyEvent->_emit_childstatus ($pid, $?) + while ($pid = waitpid -1, $WNOHANG) > 0; } sub child { @@ -2272,7 +2351,7 @@ my knowledge, there is no way to do completely race-free and quick signal handling in pure perl. To ensure that signals still get delivered, AnyEvent will start an interval timer to wake up perl (and -catch the signals) with soemd elay (default is 10 seconds, look for +catch the signals) with some delay (default is 10 seconds, look for C<$AnyEvent::MAX_SIGNAL_LATENCY>). If this module is available, then it will be used to implement signal @@ -2283,6 +2362,11 @@ This affects not just the pure-perl event loop, but also other event loops that have no signal handling on their own (e.g. Glib, Tk, Qt). +Some event loops (POE, Event, Event::Lib) offer signal watchers natively, +and either employ their own workarounds (POE) or use AnyEvent's workaround +(using C<$AnyEvent::MAX_SIGNAL_LATENCY>). Installing L +does nothing for those backends. + =item L This module isn't really "optional", as it is simply one of the backend @@ -2305,7 +2389,7 @@ This module is required when you want to read or write JSON data via L. It is also written in pure-perl, but can take -advantage of the ulta-high-speed L module when it is installed. +advantage of the ultra-high-speed L module when it is installed. In fact, L will use L by default if it is installed. @@ -2382,7 +2466,7 @@ Implementations: L, L, L, L, L, L, L, -L, L. +L, L, L. Non-blocking file handles, sockets, TCP clients and servers: L, L, L.