#!/usr/bin/perl use strict; use warnings; use Time::HiRes qw(usleep); use IPC::Open3; use IO::Handle; # ANSI color codes my $RESET = "\e[0m"; my $GREEN = "\e[32m"; # Child color my $YELLOW = "\e[33m"; # Parent color # Usage function sub usage { my ($args) = @_; print STDERR "rcvd : $0 $args\n"; print STDERR "usage:\n"; print STDERR " $0 pump \n"; print STDERR " $0 parent\n"; print STDERR " $0 child \n"; print STDERR "\n"; print STDERR "e.g:\n"; print STDERR " perl $0 pump 35 50 | perl $0 parent\n"; exit 1; } # Pump role sub pump { my ($persecond, $maxcount) = @_; if ($persecond > 1000) { print STDERR "WARNING: (>1000) sub millisecond scheduling not available - will go full speed\n"; usleep(500_000); } STDOUT->autoflush(1); STDERR->autoflush(1); my $counter = -1; my $ms = int(1000 / $persecond); while ($maxcount <= 0 || $counter < $maxcount - 1) { $counter++; print ".${counter}"; usleep($ms * 1000); } print STDERR "pump-done\n"; } # Parent role sub parent { print STDERR "${YELLOW}parent${RESET}\n"; usleep(250_000); # Read the first chunk from stdin my $parent_chunk1; read(STDIN, $parent_chunk1, 8); print STDERR "${YELLOW}${parent_chunk1}${RESET}\n"; # Launch the child process #my $child_pid = open3("<&STDIN", my $child_out, ">&STDERR", "perl", $0, "child", "150"); open(local *CHILD_STDIN, "<&", \*STDIN) or die "Can't dup STDIN: $!"; open(local *CHILD_STDERR, "<&", \*STDERR) or die "Can't dup STDERR: $!"; my $child_pid = open3("<&CHILD_STDIN", my $child_out, ">&CHILD_STDERR", "perl", $0, "child", "150"); binmode($child_out, ":utf8"); # Handle output from the child process asynchronously while (my $line = <$child_out>) { print STDERR $line; } #close $child_out; waitpid($child_pid, 0); print STDERR "parent-tail-read\n"; while (my $chunk = ) { print STDOUT $chunk; } print STDERR "\n${YELLOW}parent-done${RESET}\n"; } # Child role sub child { my ($delay_ms) = @_; print STDERR "\n${GREEN}child${RESET}\n"; usleep($delay_ms * 1000); # Read exactly 16 characters from stdin my $chunk; my $bytes_read = read(STDIN, $chunk, 16); if (defined $bytes_read) { if ($bytes_read > 0) { print STDERR "${GREEN}child-read: $bytes_read bytes${RESET}\n"; } else { print STDERR "${GREEN}child-read: no data read${RESET}\n"; exit 0; } } print STDOUT "${GREEN}${chunk}${RESET}\n"; print STDERR "child-done\n"; exit 0; } # Main function sub main { my @args = @ARGV; if (@args < 1) { usage(""); } my $role = shift @args; if ($role eq "pump") { if (@args != 2) { usage("pump"); } my ($persecond, $maxcount) = @args; pump($persecond, $maxcount); } elsif ($role eq "parent") { if (@args != 0) { usage("parent"); } parent(); } elsif ($role eq "child") { if (@args != 1) { usage("child"); } my ($delay_ms) = @args; child($delay_ms); } else { usage($role); } } main();