#!/usr/bin/perl use strict; use warnings; use IO::Handle; use MCE::Shared; use Fcntl; use Scalar::Util qw( openhandle ); use POSIX qw( WNOHANG ); my $shared; my $from_parent_one; my $to_child_one; my $from_child_one; my $to_parent_one; my $from_parent_two; my $to_child_two; my $from_child_two; my $to_parent_two; my @pipe_handles = ( $from_parent_one, $to_child_one, $from_child_one, $to_parent_one, $from_parent_two, $to_child_two, $from_child_two, $to_parent_two ); my $pid_one; my $pid_two; my $line; my $debug = $ENV{ 'DEBUG' } ? 1 : 0; my $restart = 0; my $restart_ref = \$restart; START: while ( 1 ) { print( "(Re-)Starting ...\n" ); # To be sure possibly remaining open pipe handles # are close before creating new ones # foreach my $handle ( @pipe_handles ) { close( $handle ) if defined openhandle( $handle ); } # create the pipes for process one # pipe( $from_parent_one, $to_child_one ) or die "pipe: $!"; pipe( $from_child_one, $to_parent_one ) or die "pipe: $!"; $to_child_one->autoflush(1); $to_parent_one->autoflush(1); # create the pipes for process two # pipe( $from_parent_two, $to_child_two ) or die "pipe: $!"; pipe( $from_child_two, $to_parent_two ) or die "pipe: $!"; $to_child_two->autoflush(1); $to_parent_two->autoflush(1); # Make the child's end of the pipes non-blocking # unblock( $from_child_one ); unblock( $from_child_two ); # Share a scalar between the two processes # MCE::Shared->stop(); tie $shared, 'MCE::Shared'; # To be able to do a "clean" restart, all possibly running # childs have to be terminated first # check_kill( $pid_one, 'parent' ); check_kill( $pid_two, 'parent' ); # Start the childs # $pid_one = run_one(); $pid_two = run_two(); # We need a few signal handlers to be able to terminate # the child processes (e.g. from CLI: "kill -s 10 ") # $SIG{ USR1 } = sub { kill_and_restart( $pid_one, $restart_ref ) }; #$SIG{ USR2 } = sub { $$restart_ref = 1; kill( 15 , $pid_two ) }; $SIG{ PIPE } = $SIG{ TERM } = 'IGNORE'; close( $from_parent_one ); close( $to_parent_one ); close( $from_parent_two ); close( $to_parent_two ); $shared = "Set once in parent!"; print( "Parent: \$shared: ${shared}\n" ); while ( 1 ) { # Write a message to child one # print $to_child_one "Parent with process ID $$ for child one\n" or warn( "Parent on write: $!" ); # Write a message to child two # print $to_child_two "Parent with process ID $$ for child two\n" or warn( "Parent on write: $!" ); select( undef, undef, undef, 0.5 ); # Read a message from child one # chomp( $line = <$from_child_one> ) or warn( "Parent on read: $!\n" ); print "The parent process with PID $$ received a message: '$line'\n"; # Read a message from child two # chomp( $line = <$from_child_two> ) or warn( "Parent on read: $!\n" ); print "The parent process with PID $$ received a message: '$line'\n"; dbg( "\$restart is " . $restart ); if ( $restart ) { next START } sleep( 3 ); } close $to_child_one; close $from_child_one; close $to_child_two; close $from_child_two; } sub run_one { my $pid; my $line; my $sub = 'run_one()'; unblock( $from_parent_one ); if ( ! defined ( $pid = fork() ) ) { die( "${sub}: $!" ) } return $pid if ( $pid ); # close the sides of the pipes not used by the child # close $from_child_one; close $to_child_one; print( "Child one: \$shared: ${shared}\n" ); while ( 1 ) { select( undef, undef, undef, 0.1 ); # Read a message from the parent # chomp( $line = <$from_parent_one> ) or warn( "Child, on read: $!" ); print "Child one with PID $$ received a message: '$line'\n"; select( undef, undef, undef, 0.1 ); # Write a message to the parent # print $to_parent_one "Child one with PID $$\n" or warn( "Child, on write: $!" ); sleep( 3 ); } close $from_parent_one; close $to_parent_one; return $pid } sub run_two { my $pid; my $line; my $sub = 'run_two()'; unblock( $from_parent_two ); if ( ! defined ( $pid = fork() ) ) { die( "${sub}: $!" ) } return $pid if ( $pid ); # close the sides of the pipes not used by the child # close $from_child_two; close $to_child_two; print( "Child two: \$shared: ${shared}\n" ); while ( 1 ) { select( undef, undef, undef, 0.1 ); # Read a message from the parent # chomp( $line = <$from_parent_two> ) or warn( "Child, on read: $!" ); print "Child two with PID $$ received a message: '$line'\n"; select( undef, undef, undef, 0.1 ); # Write a message to the parent # print $to_parent_two "Child two with PID $$\n" or warn( "Child, on write: $!" ); sleep( 3 ); } close $from_parent_two; close $to_parent_two; } sub unblock { my $handle = shift; my $flags = ''; my $sub = 'unblock()'; $flags = fcntl( $handle, F_GETFL, 0 ) or die( "${sub}: Could not get flags from pipe handle \: $!\n" ); fcntl( $handle, F_SETFL, $flags | O_NONBLOCK ) or die( "${sub}: Could not set flags for pipe handle: $!\n" ); return; } sub dbg { my $dbg_msg = shift(); if ( $debug ) { print( "DEBUG: ${dbg_msg}" . "\n" ); } } sub check_kill { my ( $pid, $caller_id ) = @_; my $res_pid; if ( defined $pid ) { $res_pid = waitpid( $pid, WNOHANG ); die( "waitpid: $!" ) unless $! eq ''; if ( $res_pid == -1 ) { die( "${caller_id}: Error when checking existance of child process " . "with PID ${pid}\n" ); } elsif ( $res_pid == 0 ) { kill( 15, $pid ); } } return $res_pid; } sub kill_and_restart{ my ( $pid, $restart_ref ) = @_; kill( 15, $pid ); $$restart_ref = 1; return; }