#!/usr/bin/perl
# http://perlmonks.org/?node_id=1192662
use strict;
use warnings;
use IO::Select;
my $childcount = 3;
my $hasterminal = 1;
my %who;
my %pipes;
for my $from (1 .. $childcount)
{
for my $to (1 .. $from - 1, $from + 1 .. $childcount)
{
pipe( my $readhandle, my $writehandle) or die "$! on pipe";
$writehandle->autoflush;
$pipes{$from}{$to}{rh} = $readhandle;
$pipes{$from}{$to}{wh} = $writehandle;
}
}
for my $me (1 .. $childcount)
{
if( my $pid = fork ) # parent
{
$who{$pid} = $me;
}
elsif( defined $pid ) # child
{
my $sel = IO::Select->new;
$me == $hasterminal and $sel->add(*STDIN);
for my $from (1 .. $me - 1, $me + 1 .. $childcount)
{
$sel->add($pipes{$from}{$me}{rh});
close $pipes{$from}{$me}{wh};
}
while(1)
{
for my $handle ($sel->can_read)
{
defined( my $command = <$handle> ) or exit;
print "$me got $command";
$command =~ /^(\d+)\s+(.*\n)/ and $1 != $me and
print { $pipes{$me}{$1}{wh} } $2;
}
}
}
else
{
die "fork failed with $!";
}
}
use Data::Dump 'pp'; pp \%who;
my $pid = wait; # on first exit, kill rest
print "$who{$pid} exited\n";
kill 15, keys %who;
print "$who{$pid} exited\n" while ($pid = wait) > 0;
####
2 3 foobar
##
##
1 got 2 3 foobar
2 got 3 foobar
3 got foobar