AnyEvent-FDpasser

 view release on metacpan or  search on metacpan

lib/AnyEvent/FDpasser.pm  view on Meta::CPAN


  delete $self->{$_} foreach (qw/owatcher iwatcher obuf ibuf fh fh_pair fh_duped fh_duped_orig on_error/);

  $self->{error_state} = $err;

  {
    local $@ = $err;
    $on_error->() if $on_error;
  }
}


sub DESTROY {
  my ($self) = @_;

  if (exists $self->{fh_duped}) {
    POSIX::close($self->{fh_duped});
    delete $self->{fh_duped};
  }
  if (exists $self->{fh_duped_orig}) {
    POSIX::close($self->{fh_duped_orig});
    delete $self->{fh_duped_orig};
  }
}


sub setup_fh_duped {
  my ($self) = @_;

  return if exists $self->{fh_duped};

  if (!exists $self->{fh_duped_orig}) {
    my ($r, $w) = POSIX::pipe();
    die "can't call pipe: $!" unless defined $r;
    POSIX::close($w);
    $self->{fh_duped_orig} = $r;
  }

  $self->{fh_duped} = POSIX::dup($self->{fh_duped_orig});

  if (!defined $self->{fh_duped}) {
    delete $self->{fh_duped};
    if ($!{EMFILE} || $!{ENFILE}) {
      ## Descriptor table full: have to make sure not to call recvmsg now
      $self->enter_full_descriptor_table_state;
    } else {
      die "unable to dup descriptor for reason other than full descriptor table: $!";
    }
  }
}

sub enter_full_descriptor_table_state {
  my ($self) = @_;

  return if $self->{full_descriptor_table_state};

  $self->{full_descriptor_table_state} = 1;

  undef $self->{iwatcher};

  my $watcher; $watcher = AE::timer 0.05, 0.5, sub {
    $self->setup_fh_duped;
    if (exists $self->{fh_duped}) {
      undef $watcher;
      delete $self->{full_descriptor_table_state};
      $self->try_to_recv;
    }
  };
}


1;

__END__



=head1 NAME

AnyEvent::FDpasser - pass file descriptors between processes using non-blocking buffers

=head1 SYNOPSIS

    use AnyEvent;
    use AnyEvent::FDpasser;

    my $passer = AnyEvent::FDpasser->new;

    if (fork) {
      $passer->i_am_parent;

      open(my $fh, '>>', '/tmp/fdpasser_output') || die;
      syswrite $fh, "This line is from PID $$\n";

      $passer->push_send_fh($fh);

      undef $fh; # don't close() it though
    } else {
      $passer->i_am_child;

      $passer->push_recv_fh(sub {
        my $fh = shift;

        syswrite $fh, "This line is from PID $$\n";
      });
    }

    AE->cv->recv; # AnyEvent main loop



=head1 DESCRIPTION

This module provides an object oriented interface for passing filehandles between processes. Its primary goals are API simplicity, portability, and reliability. It is suitable for use in non-blocking programs where blocking in even exceptional circum...

This module currently works on BSD4.4-like systems (*BSD, Linux, Mac OS X) where it uses the C<SCM_RIGHTS> ancillary data feature over C<AF_UNIX> sockets, on BSD4.3-like systems (Solaris, IRIX?) where it uses C<msg_accrights> field of C<msghdr> over ...

Note that a passer object is "bidrectional" and you can use the same object to both send and receive filehandles (each side has a separate input and output buffer).

After sending a filehandle, the sending process will automatically destroy it and you shouldn't close it yourself. Forgetting all references to it is what you should do so that the underlying descriptor is actually closed after it is sent. The except...



( run in 1.552 second using v1.01-cache-2.11-cpan-2398b32b56e )