Bloehdian has asked for the wisdom of the Perl Monks concerning the following question:
Hello Monks,
in the sample code below three processes are generated using fork(), the parent process and two child processes. The child processes are generated using the subs run_one and run_two.
The parent process is continuously exchanging text messages with the childs, moreover, all three processes share a variable $shared by tie()ing it to MCE::Shared. I only mention this for completeness, the sharing issue is not relrevant for the problem a hand.
What I intend to do is to send signals (to be specific, SIGUSR1 and SIGUSR2 for the child process denoted with "one" and the child process denoted with "two"., resp.) from the command line to the program (the signal handler is defined in the parent process!) and trigger kill()ing ONE of the processes (simulating a crashing of the respective child).
After kill()ing one child, the parent process should kill the remaining child using a the subroutine check_kill() and create to new child processes. This should be done by leaving the inner while(1), in which the parent does it's work, and start a new iteration of the outer while (using the label START).
My idea was to set the variable $restart to a true value when the signal arrives, so that the inner loop is left on "next START".
I created a subroutine kill_and_restart(), which is basically the signal handler, but to no avail. Since I obviously cannot change the variable $restart from within this subroutine, I cannot trigger leave of the inner while loop by use of the signal handler, not even when $restart is passed as a reference to the sub (or am I doing something wrong here?).
Restart of the two childs HAVE to be done by reiterating the outer loop, the control flow is fixed.
But: How can I reach this using the signal handler?
Cheers
Blohdian
#!/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 <pid>") # $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 pr +ocess " . "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; }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Influencing control flow using a signal handler
by Athanasius (Archbishop) on Nov 03, 2016 at 07:44 UTC | |
|
Re: Influencing control flow using a signal handler
by afoken (Chancellor) on Nov 03, 2016 at 07:42 UTC | |
|
Re: Influencing control flow using a signal handler
by tybalt89 (Monsignor) on Nov 03, 2016 at 10:32 UTC | |
|
Re: Influencing control flow using a signal handler
by Bloehdian (Beadle) on Nov 05, 2016 at 19:41 UTC |