--- AnyEvent/lib/AnyEvent.pm 2009/04/01 15:29:00 1.202 +++ AnyEvent/lib/AnyEvent.pm 2009/04/26 18:12:53 1.208 @@ -8,21 +8,28 @@ use AnyEvent; - my $w = AnyEvent->io (fh => $fh, poll => "r|w", cb => sub { ... }); + # file descriptor readable + my $w = AnyEvent->io (fh => $fh, poll => "r", cb => sub { ... }); + # one-shot or repeating timers my $w = AnyEvent->timer (after => $seconds, cb => sub { ... }); my $w = AnyEvent->timer (after => $seconds, interval => $seconds, cb => ... print AnyEvent->now; # prints current event loop time print AnyEvent->time; # think Time::HiRes::time or simply CORE::time. + # POSIX signal my $w = AnyEvent->signal (signal => "TERM", cb => sub { ... }); + # child process exit my $w = AnyEvent->child (pid => $pid, cb => sub { my ($pid, $status) = @_; ... }); + # called when event loop idle (if applicable) + my $w = AnyEvent->idle (cb => sub { ... }); + my $w = AnyEvent->condvar; # stores whether a condition was flagged $w->send; # wake up current and all future recv's $w->recv; # enters "main loop" till $condvar gets ->send @@ -322,6 +329,21 @@ difference between C<< AnyEvent->time >> and C<< AnyEvent->now >> into account. +=item AnyEvent->now_update + +Some event loops (such as L or L) cache +the current time for each loop iteration (see the discussion of L<< +AnyEvent->now >>, above). + +When a callback runs for a long time (or when the process sleeps), then +this "current" time will differ substantially from the real time, which +might affect timers and time-outs. + +When this is the case, you can call this method, which will update the +event loop's idea of "current time". + +Note that updating the time I cause some events to be handled. + =back =head2 SIGNAL WATCHERS @@ -397,6 +419,41 @@ # do something else, then wait for process exit $done->recv; +=head2 IDLE WATCHERS + +Sometimes there is a need to do something, but it is not so important +to do it instantly, but only when there is nothing better to do. This +"nothing better to do" is usually defined to be "no other events need +attention by the event loop". + +Idle watchers ideally get invoked when the event loop has nothing +better to do, just before it would block the process to wait for new +events. Instead of blocking, the idle watcher is invoked. + +Most event loops unfortunately do not really support idle watchers (only +EV, Event and Glib do it in a usable fashion) - for the rest, AnyEvent +will simply call the callback "from time to time". + +Example: read lines from STDIN, but only process them when the +program is otherwise idle: + + my @lines; # read data + my $idle_w; + my $io_w = AnyEvent->io (fh => \*STDIN, poll => 'r', cb => sub { + push @lines, scalar ; + + # start an idle watcher, if not already done + $idle_w ||= AnyEvent->idle (cb => sub { + # handle only one line, when there are lines left + if (my $line = shift @lines) { + print "handled when idle: $line"; + } else { + # otherwise disable the idle watcher again + undef $idle_w; + } + }); + }); + =head2 CONDITION VARIABLES If you are familiar with some event loops you will know that all of them @@ -875,7 +932,7 @@ use Carp; -our $VERSION = 4.35; +our $VERSION = 4.4; our $MODEL; our $AUTOLOAD; @@ -917,7 +974,8 @@ [Prima:: => AnyEvent::Impl::POE::], ); -our %method = map +($_ => 1), qw(io timer time now signal child condvar one_event DESTROY); +our %method = map +($_ => 1), + qw(io timer time now now_update signal child idle condvar one_event DESTROY); our @post_detect; @@ -932,12 +990,12 @@ push @post_detect, $cb; defined wantarray - ? bless \$cb, "AnyEvent::Util::PostDetect" + ? bless \$cb, "AnyEvent::Util::postdetect" : () } } -sub AnyEvent::Util::PostDetect::DESTROY { +sub AnyEvent::Util::postdetect::DESTROY { @post_detect = grep $_ != ${$_[0]}, @post_detect; } @@ -984,7 +1042,7 @@ } $MODEL - or die "No event module selected for AnyEvent and autodetect failed. Install any one of these modules: EV, Event or Glib."; + or die "No event module selected for AnyEvent and autodetect failed. Install any one of these modules: EV, Event or Glib.\n"; } } @@ -1024,7 +1082,7 @@ : Carp::croak "AnyEvent->io requires poll set to either 'r' or 'w'"; open my $fh2, "$mode&" . fileno $fh - or die "cannot dup() filehandle: $!"; + or die "cannot dup() filehandle: $!,"; # we assume CLOEXEC is already set by perl in all important cases @@ -1033,10 +1091,10 @@ package AnyEvent::Base; -# default implementation for now and time +# default implementations for many methods BEGIN { - if (eval "use Time::HiRes (); time (); 1") { + if (eval "use Time::HiRes (); Time::HiRes::time (); 1") { *_time = \&Time::HiRes::time; # if (eval "use POSIX (); (POSIX::times())... } else { @@ -1046,11 +1104,12 @@ sub time { _time } sub now { _time } +sub now_update { } # default implementation for ->condvar sub condvar { - bless { @_ == 3 ? (_ae_cb => $_[2]) : () }, AnyEvent::CondVar:: + bless { @_ == 3 ? (_ae_cb => $_[2]) : () }, "AnyEvent::CondVar" } # default implementation for ->signal @@ -1106,10 +1165,10 @@ undef $SIG_EV{$signal}; }; - bless [$signal, $arg{cb}], "AnyEvent::Base::Signal" + bless [$signal, $arg{cb}], "AnyEvent::Base::signal" } -sub AnyEvent::Base::Signal::DESTROY { +sub AnyEvent::Base::signal::DESTROY { my ($signal, $cb) = @{$_[0]}; delete $SIG_CB{$signal}{$cb}; @@ -1160,10 +1219,10 @@ &_sigchld; } - bless [$pid, $arg{cb}], "AnyEvent::Base::Child" + bless [$pid, $arg{cb}], "AnyEvent::Base::child" } -sub AnyEvent::Base::Child::DESTROY { +sub AnyEvent::Base::child::DESTROY { my ($pid, $cb) = @{$_[0]}; delete $PID_CB{$pid}{$cb}; @@ -1172,6 +1231,42 @@ undef $CHLD_W unless keys %PID_CB; } +# idle emulation is done by simply using a timer, regardless +# of whether the proces sis idle or not, and not letting +# the callback use more than 50% of the time. +sub idle { + my (undef, %arg) = @_; + + my ($cb, $w, $rcb) = $arg{cb}; + + $rcb = sub { + if ($cb) { + $w = _time; + &$cb; + $w = _time - $w; + + # never use more then 50% of the time for the idle watcher, + # within some limits + $w = 0.0001 if $w < 0.0001; + $w = 5 if $w > 5; + + $w = AnyEvent->timer (after => $w, cb => $rcb); + } else { + # clean up... + undef $w; + undef $rcb; + } + }; + + $w = AnyEvent->timer (after => 0.05, cb => $rcb); + + bless \\$cb, "AnyEvent::Base::idle" +} + +sub AnyEvent::Base::idle::DESTROY { + undef $${$_[0]}; +} + package AnyEvent::CondVar; our @ISA = AnyEvent::CondVar::Base::;