On Thu Jan 12 11:17:51 2017, DAKKAR wrote:
Show quoted text> A possible (vaguely tested some time ago) implementation would be:
...
I've borrowed that inspiration, and added the lines of code to actually call it at the appropriate time.
--
Paul Evans
=== modified file 'lib/IO/Async/Loop/Epoll.pm'
--- lib/IO/Async/Loop/Epoll.pm 2018-01-22 00:00:15 +0000
+++ lib/IO/Async/Loop/Epoll.pm 2018-06-25 16:03:40 +0000
@@ -117,6 +117,8 @@
$self->{signals} = {}; # {$name} => SignalWatch
$self->{masks} = {};
+ $self->{pid} = $$;
+
# epoll gets very upset if applications close() filehandles without telling
# it, and then try to add that mask a second time. We can attempt to detect
# this by storing the mapping from fileno to refaddr($fh)
@@ -165,6 +167,8 @@
my $self = shift;
my ( $timeout ) = @_;
+ $self->post_fork if $self->{pid} != $$;
+
$self->_adjust_timeout( \$timeout );
# Round up to next milisecond to avoid zero timeouts
@@ -234,6 +238,8 @@
my $self = shift;
my %params = @_;
+ $self->post_fork if $self->{pid} != $$;
+
my $epoll = $self->{epoll};
$self->__watch_io( %params );
@@ -319,6 +325,8 @@
my $self = shift;
my %params = @_;
+ $self->post_fork if $self->{pid} != $$;
+
$self->__unwatch_io( %params );
my $epoll = $self->{epoll};
@@ -413,6 +421,26 @@
sigprocmask( SIG_UNBLOCK, POSIX::SigSet->new( $signum ) );
}
+sub post_fork
+{
+ my $self = shift;
+
+ $self->{epoll} = Linux::Epoll->new;
+ $self->{pid} = $$;
+
+ my $watches = $self->{iowatches} or return;
+
+ foreach my $watch ( values %$watches ) {
+ my ( $handle, $on_read_ready, $on_write_ready, $on_hangup ) = @$watch;
+ $self->watch_io(
+ handle => $handle,
+ on_read_ready => $on_read_ready,
+ on_write_ready => $on_write_ready,
+ on_hangup => $on_hangup,
+ );
+ }
+}
+
=head1 SEE ALSO
=over 4
=== added file 't/10loop-fork.t'
--- t/10loop-fork.t 1970-01-01 00:00:00 +0000
+++ t/10loop-fork.t 2018-06-25 16:03:40 +0000
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+use IO::Async::OS;
+use IO::Async::Loop::Epoll;
+
+plan skip_all => "Cannot fork" unless IO::Async::OS->HAVE_POSIX_FORK;
+
+my $loop = IO::Async::Loop::Epoll->new;
+
+my @kids = map {
+ defined( my $pid = fork ) or die "Cannot fork() - $!";
+ if( $pid ) {
+ $pid;
+ }
+ else {
+ test_in_child();
+ exit 0;
+ }
+} 1 .. 3;
+
+sub test_in_child
+{
+ my ( $rd, $wr ) = IO::Async::OS->pipepair;
+
+ my $readable;
+
+ $loop->watch_io(
+ handle => $rd,
+ on_read_ready => sub { $readable++ },
+ );
+
+ sleep 1;
+
+ $wr->autoflush;
+ $wr->print( "HELLO\n" );
+
+ my $count = 5;
+
+ $loop->loop_once( 0.1 ) until $readable or !$count--;
+
+ die "[$$] FAILED\n" if !$readable;
+}
+
+foreach my $kid ( @kids ) {
+ waitpid $kid, 0;
+ is( $?, 0, "Child $kid exited OK" );
+}
+
+done_testing;