AnyEvent-FDpasser
view release on metacpan or search on metacpan
lib/AnyEvent/FDpasser.pm view on Meta::CPAN
delete $self->{fh_pair};
}
sub push_send_fh {
my ($self, $fh_to_send, $cb) = @_;
die "passer object is in error_state: $self->{error_state}" if exists $self->{error_state};
die "must call i_am_parent or i_am_child" if exists $self->{fh_pair};
$cb ||= sub {};
push @{$self->{obuf}}, [$fh_to_send, $cb];
$self->try_to_send;
}
sub push_recv_fh {
my ($self, $cb) = @_;
die "passer object is in error_state: $self->{error_state}" if exists $self->{error_state};
die "must call i_am_parent or i_am_child" if exists $self->{fh_pair};
push @{$self->{ibuf}}, $cb;
$self->try_to_recv;
}
sub try_to_send {
my ($self) = @_;
return unless $self->{fh};
return unless @{$self->{obuf}};
return if defined $self->{owatcher};
return if defined $self->{full_descriptor_table_state};
$self->{owatcher} = AE::io $self->{fh}, 1, sub {
my $fh_to_send = shift @{$self->{obuf}};
my $rv = send_fd(fileno($self->{fh}), fileno($fh_to_send->[0]));
if ($rv < 0) {
if ($!{EAGAIN} || $!{EWOULDBLOCK} || $!{EINTR}) {
## Spurious ready notification or signal: put fh back on queue
unshift @{$self->{obuf}}, $fh_to_send;
} else {
## Unknown error
$self->error($!);
}
} elsif ($rv == 0) {
$self->error('sendmsg wrote 0 bytes');
} else {
$fh_to_send->[1]->();
## Don't do a close($fh_to_send->[0]) because the program may wish to keep it alive
undef $fh_to_send;
$self->{owatcher} = undef;
$self->try_to_send;
}
};
}
sub try_to_recv {
my ($self) = @_;
return unless @{$self->{ibuf}};
return if defined $self->{iwatcher};
return if defined $self->{full_descriptor_table_state};
$self->{iwatcher} = AE::io $self->{fh}, 0, sub {
my $cb = shift @{$self->{ibuf}};
POSIX::close($self->{fh_duped});
delete $self->{fh_duped};
## Race condition: If another thread or a signal handler creates a new descriptor at this
## exact point in time, it could cause the descriptor table to fill up and the following
## to error.
my $rv = recv_fd(fileno($self->{fh}));
if ($rv == -1) {
if ($!{EAGAIN} || $!{EWOULDBLOCK} || $!{EINTR}) {
## Spurious ready notification or signal: put the cb back on the queue
unshift @{$self->{ibuf}}, $cb;
} elsif ($!{EMSGSIZE} || $!{EMFILE} || $!{ENFILE}) {
## File descriptor table is full. This should be very unlikely given the close+duping
## technique used to detect this. In this case the descriptor stream may be
## desynchronised and we must shutdown the passer.
my $err = $!;
carp "AnyEvent::FDpasser - file descriptor table full, closing passer: $!";
$self->error($err);
} else {
## Unknown error
$self->error($!);
}
} elsif ($rv == -2) {
$self->error("cmsg truncated");
} elsif ($rv == 0) {
## Orderly shutdown
$self->error(undef);
} else {
open(my $new_fh, '+<&=', $rv);
$self->{iwatcher} = undef;
$cb->($new_fh);
$self->try_to_recv;
}
};
( run in 0.620 second using v1.01-cache-2.11-cpan-df04353d9ac )