Bloehdian has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I wrote a test application in which the process is forked. The resulting parent process sends a message continuously via pipe using syswrite to the child.

I installed a signal handler in the parent for signal SIGHUP, so that I can "advice" the parent from the command line to terminate the child (on sending SIGHUP to the parent process). At least I try to do this.

Here is the code:

use strict; use warnings; use Errno qw( EWOULDBLOCK ) ; my $from_parent; my $to_child; my $pid; my $mesg_parent = "Hello Child!"; my $mesg_child; my $test; pipe( $from_parent, $to_child ); if ( $pid = fork() ) { # Parent $SIG{ HUP } = sub{ kill( 15 , $pid ); print( "KILLED CHILD!!!\n" ) +}; close( $from_parent ); while ( 1 ) { eval{ $test = syswrite( $to_child, $mesg_parent, length( $mesg_p +arent ) ); }; select( undef, undef, undef, .5); if ( $@ ) { print( "trapped error when writing to pipe \$to_child_ssl\n" +); next; } if ( defined $test ) { print( "Sent message \"$mesg_parent\" to child\n" ); } } } else { # Child close( $to_child ); while ( 1 ) { $test = sysread( $from_parent, $mesg_child, 13 ); select( undef, undef, undef, .5 ); if ( ! defined $test ) { if ( $! == EWOULDBLOCK ) { print( "sysread would be blocked by \$from_parent: $!\n" ) +; next; } else { die ( "Error when trying to read from \$from_parent: $!\n" + ); } } print( "In child\n" ); print( $mesg_child . "\n" ); $mesg_child =~ s/Child/Parent/; print $mesg_child . "\n"; } }

When I run the script and execute

kill -1 <pid>

in a different terminal window with <pid> being the parent process's PID than the final output is as follows:

Sent message "Hello Child!" to child In child Hello Child! Hello Parent! Sent message "Hello Child!" to child In child Hello Child! Hello Parent! KILLED CHILD!!! Sent message "Hello Child!" to child Sent message "Hello Child!" to child xyz@v32470:~/projekte/$

i.e., not only the child´, but the parent as well is terminated.

If I use

kill 1 <pid>

then obviously only the parent process is killed, the child continues to run:

In child Hello Child! Hello Parent! Terminated xyz@v32470:~/projekte$ In child Hello Child! Hello Parent! In child In child In child In child

The kill command comes back with an error message btw:

xyz@v32470:~$ kill 1 31055 -bash: kill: (1) - Operation not permitted

How can this behaviour explained and how could I reach that only the child is killed by the parent and the parent continues to work?

The backgroud: I want to use this code as the basis for a script in which the parent checks whether the child is still running by sending messages via pipe to the child and checks the response (i.e., in the final version the communication would be bidirectional).

Is this feasible using this approach at all?

From my ´point of view it boils down to the qestion whether I could trap an error as indicated in the script when trying to syswrite() to the üipe after the child passed away. Is this possible?

Cheers Bloehdian

Replies are listed 'Best First'.
Re: fork(): terminating the child without killing the parent
by tybalt89 (Monsignor) on Oct 26, 2016 at 04:02 UTC

    Here's a version that uses that SIGPIPE to restart a child ( with a new pipe ), but things had to be shuffled around a bit.

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1174747 use strict; use warnings; $| = 1; my ($from_parent, $to_child ); while(1) { my $msg = "hello from $$\n"; print "pipe and fork, parent $$\n"; pipe( $from_parent, $to_child ) or die "$! on pipe"; if( my $pid = fork ) { # parent close $from_parent; my $more = 1; $SIG{HUP} = sub { $pid and kill 15, $pid }; $SIG{PIPE} = sub { $more = 0 }; while($more) { syswrite $to_child, $msg, length $msg; sleep 3; } } elsif( defined $pid ) { # child close $to_child; print "child $$ started\n"; while(1) { if( sysread $from_parent, my $buffer, 100 ) { print "in child $$: $buffer"; } } exit; } else { die "$! on fork"; } }
Re: fork(): terminating the child without killing the parent
by hippo (Archbishop) on Oct 26, 2016 at 08:05 UTC
    The kill command comes back with an error message btw:
    xyz@v32470:~$ kill 1 31055 -bash: kill: (1) - Operation not permitted

    Of course. PID 1 is init and you'd better hope that an unprivileged user cannot kill that.

Re: fork(): terminating the child without killing the parent
by tybalt89 (Monsignor) on Oct 26, 2016 at 03:21 UTC

    Your parent dies because it got a SIGPIPE