Re: Child process dies
by jettero (Monsignor) on Jan 05, 2007 at 15:04 UTC
|
You can $SIG{__DIE__} = sub { kill 15, $kidpid }; or something like that, but don't think you'll have time to do anything in your parent process if it gets hit with a -9 (assuming it's a SIGKILL on your platform). Traditionally you can't install a handler for that one.
UPDATE: I just noticed that you specifically don't want to kill from the parent — which makes sense if you're anticipiating the parent dying from a SIGKILL. The only other thing I can think of is polling. Either store a $rentid = $$ before your fork and check to see if the rent is still there with say -d "/proc/$rentid" (not very accurate in some cases) or possibly by using a lockfile (see flock) that the parent keeps locked and the child non-blockingly checks for locks.
| [reply] [d/l] [select] |
Re: Child process dies
by kyle (Abbot) on Jan 05, 2007 at 15:29 UTC
|
You could make another child whose job is only to wait on the parent's death and then kill the first child. jettero's suggestion of a lock file would be a good way for the watchdog child to notice the parent's death without polling. The whole process would look a little like:
- Parent flocks a file.
- Parent forks child 1 (records PID—child 2 will need it).
- Parent forks child 2.
- Child 2 does a blocking flock on the same file (and so hangs).
- There is joy in Mudville.
- Parent receives deadly signal 9. Parent's lock is released.
- Child 2 gets the lock and continues. It's next (unconditional) action is to kill child 1 and exit.
- Child 1 dies from the signal from child 2.
- And then there were none.
| [reply] [d/l] [select] |
Re: Child process dies
by ikegami (Patriarch) on Jan 05, 2007 at 15:20 UTC
|
There's presumably a communication channel (a pipe?) between the parent and the child. You could periodically check the status of the communication channel.
If your communication channel is a pipe, then all you have to do is suicide when you receive a SIGPIPE signal. I think that might even be the default action! (This won't work in Windows.)
| [reply] |
|
|
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. | [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] [select] |
|
|
|
|
|
|
A variation on this is to write the whole thing in a select loop, which waits for the filehandle from the parent to become readable and any other conditions. The parent filehandle will become readable as soon as it exits, and a read will return an end-of-file indicator.
| [reply] |
Re: Child process dies
by derby (Abbot) on Jan 05, 2007 at 15:56 UTC
|
Well first off, SIGKILL (9) is untrappable and unignorable. You could choose to send SIGTERM (15) which has always been the *nicer* way to terminate a process. If you choose to do that, then you would need to setup a signal handler in your parent process that would then send a signal to the process group. (This, of course, all depends on how your platform handles signals and processes!):
#!/usr/local/bin/perl
# parent code
use strict;
use warnings;
my $pid;
$SIG{TERM} = \&catch_sig;
if( $pid = fork ) {
# parent
while( 1 ) {
print "parent: $$, ", getpgrp, "\n";
sleep 2;
}
} else {
exec ('./child.pl') or die "couldn't exec child.pl: $!";
}
sub catch_sig {
kill -15, getpgrp;
exit;
}
#!/usr/local/bin/perl
#child code --- nothing special here
use strict;
use warnings;
while( 1 ) {
print "child: $$, ", getpgrp, "\n";
sleep( 3 );
}
Now if you send kill -15 parent_process_id from the shell, the signal is trapped and then propagated to the group.
| [reply] [d/l] [select] |
Re: Child process dies
by Fletch (Bishop) on Jan 05, 2007 at 15:13 UTC
|
In general the OS will provide the parent notification when the child goes away automatically; what you're trying to do is bass ackwards from the way things normally work on most *NIXen. You may get better answers if you explain what you're trying to do by this rather than seeking a mechanism you think will accomplish it.
| [reply] |
|
|
What I want to do is following: one parent process is creating lisening server process. This parent is forking a child which is "log maintainer" - it logs all the activity of parent/child processes into file and maintains that file size. Log maintainer (child process) is active all the time. What I want to complish is when I kill parent I want child to die instantly as well. I do not want to kill 2 processes in order to shut the functionality. Now I did this by means of two techniques:
1. child periodically checks if parentpid exists. If there is no parent pid it exists ; or
2. When parent is killed with INT signal - there is a signal handler for upon receiving the INT - it will kill child and then parent.
Those aproaches are with flaws:
1. I want child instantly killed when parent is killled and not to check periodicly!
2. What if parent is killed by other means than INT signal?
-Dejan.
| [reply] |
|
|
| [reply] |
|
|
Let the parent kill the child but install more than one handler, not just INT. You definitely want TERM and possibly QUIT. There's no point in installing a handler for KILL as imp and jettero point out.Cheers, JohnGG
| [reply] |
|
|
Okay, then, swap your processes' parentage. Make the "log maintainer" be the parent, and have it spawn the "doit" job. Then, when the doit job exits, the log maintainer job will notice it, and you can have it shut down gracefully.....
Roboticus
| [reply] |
Re: Child process dies
by Anonymous Monk on Jan 05, 2007 at 20:27 UTC
|
Ummm. A "/bin/kill -s SIGTERM -<process group>" will send the same signal to all the processes in the process group. Unless your child process has a different process group, or you want the child to die *strictly* after the parent (I believe order of signal delivery is undefined with respect to members of a process group), then why not just do it this way? | [reply] |
|
|
In Perl, you can just {local $SIG{'TERM'} = 'IGNORE'; kill 15, -$$}, which should achieve the same thing without forking, since kill with a negative process ID sends it to the whole group.
| [reply] [d/l] |