AnyEvent

 view release on metacpan or  search on metacpan

lib/AnyEvent/Impl/IOAsync.pm  view on Meta::CPAN

back when I learned that the only "async" aspect of it is the name).

=item Inconsistent, incomplete and convoluted API

Implementing AnyEvent's rather simple timers on top of IO::Async's timers
was a nightmare (try implementing a timer with configurable interval and
delay value...).

The method naming is chaotic: C<watch_child> creates a child watcher,
but C<watch_io> is an internal method; C<detach_signal> removes a signal
watcher, but C<detach_child> forks a subprocess and so on).

=item Unpleasant surprises on GNU/Linux

When you develop your program on FreeBSD and run it on GNU/Linux, you
might have unpleasant surprises, as IO::Async::Loop will by default use
L<IO::Async::Loop::Epoll>, which is incompatible with C<fork>, so your
network server will run into spurious and very hard to debug problems
under heavy load, as IO::Async forks a lot of processes, e.g. for DNS
resolution. It would be better if IO::Async would only load "safe"
backends by default (or fix the epoll backend to work in the presence of
fork, which admittedly is hard - EV does it for you, and also does not use
unsafe backends by default).

=back

On the positive side, performance with IO::Async is quite good even in my
very demanding eyes.

=cut

package AnyEvent::Impl::IOAsync;

use AnyEvent (); BEGIN { AnyEvent::common_sense }

use Time::HiRes ();
use Scalar::Util ();

use IO::Async::Loop 0.33;

our $LOOP = new IO::Async::Loop;

sub set_loop($) {
   $LOOP = $_[0];
}

sub timer {
   my ($class, %arg) = @_;
   
   my $cb = $arg{cb};

   my $id;

   if (my $ival = $arg{interval}) {
      my $ival_cb; $ival_cb = sub {
         $id = $LOOP->enqueue_timer (delay => $ival, code => $ival_cb);
         &$cb;
      };
      $id = $LOOP->enqueue_timer (delay => $arg{after}, code => $ival_cb);

      # we have to weaken afterwards, but when enqueue dies, we have a memleak.
      # still, we do anything for speed...
      Scalar::Util::weaken $ival_cb;

   } else {
      # IO::Async has problems with overloaded objects
      $id = $LOOP->enqueue_timer (delay => $arg{after}, code => sub {
         undef $id; # IO::Async <= 0.43 bug workaround
         &$cb;
      });
   }

   bless \\$id, "AnyEvent::Impl::IOAsync::timer"
}

sub AnyEvent::Impl::IOAsync::timer::DESTROY {
   # Need to be well-behaved during global destruction
   $LOOP->cancel_timer (${${$_[0]}})
      if defined ${${$_[0]}}; # IO::Async <= 0.43 bug workaround
}

sub io {
   my ($class, %arg) = @_;

   # Ensure we have a real IO handle, and not just a UNIX fd integer
   my ($fh) = AnyEvent::_dupfh $arg{poll}, $arg{fh};

   my $event = $arg{poll} eq "r" ? "on_read_ready" : "on_write_ready";

   $LOOP->watch_io (
      handle => $fh,
      $event => $arg{cb},
   );

   bless [$fh, $event], "AnyEvent::Impl::IOAsync::io"
}

sub AnyEvent::Impl::IOAsync::io::DESTROY {
   $LOOP->unwatch_io (
      handle => $_[0][0],
      $_[0][1] => 1,
   );
}

sub signal {
   my ($class, %arg) = @_;

   my $signal = $arg{signal};

   my $id = $LOOP->attach_signal ($arg{signal}, $arg{cb});
   bless [$signal, $id], "AnyEvent::Impl::IOAsync::signal"
}

sub AnyEvent::Impl::IOAsync::signal::DESTROY {
   $LOOP->detach_signal (@{ $_[0] });
}

our %pid_cb;

sub child {
   my ($class, %arg) = @_;

   my $pid = $arg{pid};



( run in 0.551 second using v1.01-cache-2.11-cpan-39bf76dae61 )