in reply to Re: Child process dies
in thread Child process dies

I was trying that but I can't seem to make it work. I kill (-15) the parent but the child carries on regardless. I have made the parent the reader and child the writer and have tried it the other way around. I'm using a short sleep in a loop in the child to mimic periodic activity. Using Perl 5.8.4 on SPARC/Solaris 9. Here's the script.

use strict; use warnings; use IO::Pipe; $SIG{PIPE} = sub {exit;}; print qq{Parent PID $$\n}; my $pipeFH = IO::Pipe->new(); my $pid; if ($pid = fork) { $pipeFH->writer(); print qq{Kid is PID $pid\n}; } elsif(defined($pid)) { $pipeFH->reader(); sleep 1 for 1 .. 100; exit; } while ((my $returnPid = wait) != -1) { print qq{Kid $returnPid returned\n}; }

Maybe there is a flaw in my attempt.

Cheers,

JohnGG

Update: The flaws in my attempts were twofold. Firstly, frodo72 pointed out that the SIGPIPE would not be generated until the child process tried to do I/O on the pipe that had been closed at the other end because the parent had been killed. Secondly, it appears that IO::Pipe is somehow consuming the SIGPIPE before the child sees it so the child carries on oblivious to it's parent's death. Again, frodo72 discovered this by refactoring my code to use pipe instead of IO::Pipe.

frodo72 ++ and thanks for all the help.

Replies are listed 'Best First'.
Re^3: Child process dies
by polettix (Vicar) on Jan 05, 2007 at 19:41 UTC
    IIRC the SIGPIPE signal should be sent only when the one end tries to do I/O on a pipe that is closed on the other end. Moreover... why sleep 1 for 1 .. 100; instead of sleep 100;?

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
      Why the sleep 1 for 1 .. 100;? My ignorance really; I wasn't sure whether the script, like my daughter, would sleep through the alarm so I decided to try lots of small sleeps after it didn't work with one long sleep.

      I was already trying things like explicitly closing the pipe in the parent if it caught a signal. Following your post I have modified the script so the child keeps printing a "heartbeat" to the pipe but still to no avail. Here's the modified script.

      use strict; use warnings; use IO::Pipe; my $pipeFH; my $rcHandler = sub {$pipeFH->close(); exit;}; $SIG{INT} = $rcHandler; $SIG{QUIT} = $rcHandler; $SIG{TERM} = $rcHandler; print qq{Parent PID $$\n}; $pipeFH = IO::Pipe->new(); my $pid; if ($pid = fork) { $pipeFH->reader(); print qq{Kid is PID $pid\n}; } elsif(defined($pid)) { $SIG{PIPE} = sub {exit;}; $pipeFH->writer(); $pipeFH->print(qq{Kid: Snoozing\n}); for my $heartbeat ( 1 .. 30 ) { $pipeFH->print(qq{Kid: Heartbeat $heartbeat\n}); sleep 1; } $pipeFH->print(qq{Kid: Waking\n}); print qq{Kid: Quitting\n}; exit; } while ((my $returnPid = wait) != -1) { print qq{Kid $returnPid returned\n}; } while (defined(my $line = $pipeFH->getline())) { print qq{Read: $line}; }

      I had been killing the parent with a kill -15 (TERM) from another shell but I noticed that the child does go away immediately if I Ctrl-C the running parent. Is it the case that child processes also get an INT if the parent gets one from the shell?

      Cheers,

      JohnGG

        Update In the code below the main difference with respect to johngg's version is the use of the straight pipe function instead of IO::Pipe. It turned out (thanks to johngg's tests) that using straight pipes allowed him to trap the PIPE signal, which he couldnt' using the module. I tried to peek into the module and found nothing about SIGPIPE trapping, but I didn't dig this up to the modules included by IO::Pipe.

        Linux box with a slightly modified version of your script, and the parent signalled from another shell:

        #!/usr/bin/perl use strict; use warnings; my $whoami; sub handler { print {*STDERR} "$whoami: handler [@_]\n"; exit 0; } $SIG{INT} = \&handler; $SIG{QUIT} = \&handler; $SIG{TERM} = \&handler; $SIG{PIPE} = \&handler; END { print {*STDERR} "$whoami in END block\n"; } print {*STDERR} qq{Parent PID $$\n}; pipe my $r, my $w; my $pid; if ($pid = fork) { $whoami = 'parent'; close $w; print {*STDERR} qq{Kid is PID $pid\n}; while (<$r>) { print {*STDERR} "parent received: $_"; } print {*STDERR} "parent exiting normally\n"; exit 0; } ## end if ($pid = fork) elsif (defined($pid)) { select $w; $|++; $whoami = 'kid'; close $r; print {$w} qq{Kid: Snoozing\n}; for my $heartbeat (1 .. 30) { print {$w} qq{Kid: Heartbeat $heartbeat\n}; sleep 1; } print {$w} qq{Kid: Waking\n}; print {*STDERR} qq{Kid: Quitting\n}; exit; } ## end elsif (defined($pid)) __END__ poletti@PolettiX:~/sviluppo/perl$ perl johngg.pl Parent PID 5336 Kid is PID 5337 parent received: Kid: Snoozing parent received: Kid: Heartbeat 1 parent received: Kid: Heartbeat 2 parent received: Kid: Heartbeat 3 parent received: Kid: Heartbeat 4 parent received: Kid: Heartbeat 5 parent: handler [TERM] parent in END block poletti@PolettiX:~/sviluppo/perl$ kid: handler [PIPE] kid in END block

        Note that after the parent exits the shell regains control, hence the prompt. Within a second, the kid is trying to write to the pipe and gets signalled. Also note the following run (stopped with CTRL-C):

        poletti@PolettiX:~/sviluppo/perl$ perl johngg.pl Parent PID 5348 Kid is PID 5349 parent received: Kid: Snoozing parent received: Kid: Heartbeat 1 parent received: Kid: Heartbeat 2 parent received: Kid: Heartbeat 3 parent: handler [INT] parent in END block kid: handler [INT] kid in END block

        Both processes get the INT signal: probably the shell sends the signal to the whole process group.

        Flavio
        perl -ple'$_=reverse' <<<ti.xittelop@oivalf

        Don't fool yourself.