--- AnyEvent/lib/AnyEvent.pm 2009/05/13 13:36:49 1.209 +++ AnyEvent/lib/AnyEvent.pm 2009/06/23 12:19:33 1.215 @@ -1,8 +1,9 @@ =head1 NAME -AnyEvent - provide framework for multiple event loops +AnyEvent - provide framework for multiple event loops -EV, Event, Glib, Tk, Perl, Event::Lib, Qt, POE - various supported event loops +EV, Event, Glib, Tk, Perl, Event::Lib, Qt and POE are various supported +event loops. =head1 SYNOPSIS @@ -932,7 +933,7 @@ use Carp; -our $VERSION = 4.41; +our $VERSION = 4.411; our $MODEL; our $AUTOLOAD; @@ -943,8 +944,11 @@ our $WIN32; BEGIN { - my $win32 = ! ! ($^O =~ /mswin32/i); - eval "sub WIN32(){ $win32 }"; + eval "sub WIN32(){ " . (($^O =~ /mswin32/i)*1) ." }"; + eval "sub TAINT(){ " . (${^TAINT}*1) . " }"; + + delete @ENV{grep /^PERL_ANYEVENT_/, keys %ENV} + if ${^TAINT}; } our $verbose = $ENV{PERL_ANYEVENT_VERBOSE}*1; @@ -1143,15 +1147,15 @@ pipe $SIGPIPE_R, $SIGPIPE_W; fcntl $SIGPIPE_R, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK if $SIGPIPE_R; fcntl $SIGPIPE_W, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK if $SIGPIPE_W; # just in case + + # not strictly required, as $^F is normally 2, but let's make sure... + fcntl $SIGPIPE_R, &Fcntl::F_SETFD, &Fcntl::FD_CLOEXEC; + fcntl $SIGPIPE_W, &Fcntl::F_SETFD, &Fcntl::FD_CLOEXEC; } $SIGPIPE_R or Carp::croak "AnyEvent: unable to create a signal reporting pipe: $!\n"; - # not strictly required, as $^F is normally 2, but let's make sure... - fcntl $SIGPIPE_R, &Fcntl::F_SETFD, &Fcntl::FD_CLOEXEC; - fcntl $SIGPIPE_W, &Fcntl::F_SETFD, &Fcntl::FD_CLOEXEC; - $SIG_IO = AnyEvent->io (fh => $SIGPIPE_R, poll => "r", cb => \&_signal_exec); } @@ -1173,7 +1177,10 @@ delete $SIG_CB{$signal}{$cb}; - $SIG{$signal} = 'DEFAULT' unless keys %{ $SIG_CB{$signal} }; + # delete doesn't work with older perls - they then + # print weird messages, or just unconditionally exit + # instead of getting the default action. + undef $SIG{$signal} unless keys %{ $SIG_CB{$signal} }; } # default implementation for ->child @@ -1181,24 +1188,13 @@ our %PID_CB; our $CHLD_W; our $CHLD_DELAY_W; -our $PID_IDLE; our $WNOHANG; -sub _child_wait { +sub _sigchld { while (0 < (my $pid = waitpid -1, $WNOHANG)) { $_->($pid, $?) for (values %{ $PID_CB{$pid} || {} }), (values %{ $PID_CB{0} || {} }); } - - undef $PID_IDLE; -} - -sub _sigchld { - # make sure we deliver these changes "synchronous" with the event loop. - $CHLD_DELAY_W ||= AnyEvent->timer (after => 0, cb => sub { - undef $CHLD_DELAY_W; - &_child_wait; - }); } sub child { @@ -1209,9 +1205,7 @@ $PID_CB{$pid}{$arg{cb}} = $arg{cb}; - unless ($WNOHANG) { - $WNOHANG = eval { local $SIG{__DIE__}; require POSIX; &POSIX::WNOHANG } || 1; - } + $WNOHANG ||= eval { local $SIG{__DIE__}; require POSIX; &POSIX::WNOHANG } || 1; unless ($CHLD_W) { $CHLD_W = AnyEvent->signal (signal => 'CHLD', cb => \&_sigchld); @@ -1232,7 +1226,7 @@ } # idle emulation is done by simply using a timer, regardless -# of whether the proces sis idle or not, and not letting +# of whether the process is idle or not, and not letting # the callback use more than 50% of the time. sub idle { my (undef, %arg) = @_; @@ -1348,7 +1342,11 @@ =head1 ENVIRONMENT VARIABLES The following environment variables are used by this module or its -submodules: +submodules. + +Note that AnyEvent will remove I environment variables starting with +C from C<%ENV> when it is loaded while taint mode is +enabled. =over 4 @@ -1898,6 +1896,58 @@ =back +=head2 THE IO::Lambda BENCHMARK + +Recently I was told about the benchmark in the IO::Lambda manpage, which +could be misinterpreted to make AnyEvent look bad. In fact, the benchmark +simply compares IO::Lambda with POE, and IO::Lambda looks better (which +shouldn't come as a surprise to anybody). As such, the benchmark is +fine, and shows that the AnyEvent backend from IO::Lambda isn't very +optimal. But how would AnyEvent compare when used without the extra +baggage? To explore this, I wrote the equivalent benchmark for AnyEvent. + +The benchmark itself creates an echo-server, and then, for 500 times, +connects to the echo server, sends a line, waits for the reply, and then +creates the next connection. This is a rather bad benchmark, as it doesn't +test the efficiency of the framework, but it is a benchmark nevertheless. + + name runtime + Lambda/select 0.330 sec + + optimized 0.122 sec + Lambda/AnyEvent 0.327 sec + + optimized 0.138 sec + Raw sockets/select 0.077 sec + POE/select, components 0.662 sec + POE/select, raw sockets 0.226 sec + POE/select, optimized 0.404 sec + + AnyEvent/select/nb 0.085 sec + AnyEvent/EV/nb 0.068 sec + +state machine 0.134 sec + +The benchmark is also a bit unfair (my fault) - the IO::Lambda +benchmarks actually make blocking connects and use 100% blocking I/O, +defeating the purpose of an event-based solution. All of the newly +written AnyEvent benchmarks use 100% non-blocking connects (using +AnyEvent::Socket::tcp_connect and the asynchronous pure perl DNS +resolver), so AnyEvent is at a disadvantage here as non-blocking connects +generally require a lot more bookkeeping and event handling than blocking +connects (which involve a single syscall only). + +The last AnyEvent benchmark additionally uses L, which +offers similar expressive power as POE and IO::Lambda (using conventional +Perl syntax), which means both the echo server and the client are 100% +non-blocking w.r.t. I/O, further placing it at a disadvantage. + +As you can see, AnyEvent + EV even beats the hand-optimised "raw sockets +benchmark", while AnyEvent + its pure perl backend easily beats +IO::Lambda and POE. + +And even the 100% non-blocking version written using the high-level (and +slow :) L abstraction beats both POE and IO::Lambda, +even thought it does all of DNS, tcp-connect and socket I/O in a +non-blocking way. + =head1 SIGNALS @@ -1964,7 +2014,7 @@ Similar considerations apply to $ENV{PERL_ANYEVENT_VERBOSE}, as that can be used to probe what backend is used and gain other information (which is probably even less useful to an attacker than PERL_ANYEVENT_MODEL), and -$ENV{PERL_ANYEGENT_STRICT}. +$ENV{PERL_ANYEVENT_STRICT}. =head1 BUGS