Massyn has asked for the wisdom of the Perl Monks concerning the following question:
#!/fellow/monks.pl
On both AIX and Mandrake Linux, I'm experiencing a problem where programs spawned from within a perl script doesn't get killed when the parent dies. Yeah, children should live longer than their parents, but not in a perl script, I would think. Here's my code (and I've tried many different ways of opening tail)..
#!/usr/bin/perl
open (HTML, "-|") or exec("tail","-f","testlog.txt");
print while <HTML>;
So touch testlog.txt, run the script, and start a 2nd session. Do a ps -ef and you'll see the process running, along with the spawned tail. Kill the parent, and the child becomes almost orphaned, using the inittab as it's parent.
How can I kill the child when the parent dies, or at least spawn the child that it's dependant on the parent's survival??
[gmassyn@apt01m04 gmassyn]$ ps -ef |grep test
gmassyn 7755 7712 0 21:57 pts/0 00:00:00 /usr/bin/perl ./testb.
+pl
gmassyn 7756 7755 0 21:57 pts/0 00:00:00 tail -f testlog.txt
gmassyn 7758 7712 0 21:57 pts/0 00:00:00 grep test
[gmassyn@apt01m04 gmassyn]$ kill -9 7755
[gmassyn@apt01m04 gmassyn]$
[1]+ Killed ./testb.pl
[gmassyn@apt01m04 gmassyn]$ ps -ef |grep test
gmassyn 7756 1 0 21:57 pts/0 00:00:00 tail -f testlog.txt
gmassyn 7764 7712 0 21:57 pts/0 00:00:00 grep test
[gmassyn@apt01m04 gmassyn]$
Thanks!
|\/| _. _ _ ._
www. | |(_|_>_>\/| | .net
/
The more I learn the more I realise I don't know.
- Albert Einstein
Re: Automatically killing a child
by BrowserUk (Patriarch) on May 19, 2006 at 04:02 UTC
|
See perlopentut for details, but note that piped-opens return the pid of the forked child.
#!/usr/bin/perl
my $kid = open (HTML, "-|") or exec("tail","-f","testlog.txt");
print while <HTML>;
kill 2, $kid;
You can use that to kill or wait or waitpid, but as tail -f file will never terminate* unless the file goes away, you will probably need to kill it.
That said, if the file never goes away, tail will never terminate, so your print while <HTML> will never get eof, so you will never exit that loop in order to try and use kill.
*those versions of tail I've used.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
Re: Automatically killing a child
by Zaxo (Archbishop) on May 19, 2006 at 04:32 UTC
|
I'm surprised that the child doesn't terminate, since that is the action of the system default SIGHUP handler. If open or something else modifies that handler to keep the process running, this,
local $SIG{HUP} = sub { exit 0 };
should make sure the child terminates right after the parent does.
| [reply] [d/l] |
Re: Automatically killing a child
by mojotoad (Monsignor) on May 19, 2006 at 08:16 UTC
|
You know, every now and then this happens. You're cruising along, monitoring your various ssh sessions, browsing the web in between bursts of programming, and you come across a subject line such as this.
It's good, every now and then, to be emphatically reminded that we don't quite live in the real world.
:)
Matt | [reply] |
|
| [reply] |
Re: Automatically killing a child
by ioannis (Abbot) on May 19, 2006 at 03:10 UTC
|
For the two-argument open() , the '-|' argument means fork.
The parent can reap the children with wait(), or waitpid(),
or for some operating systems can reap them automatically
by setting the CHLD signal. See perlipc for examples. | [reply] |
Re: Automatically killing a child
by sgifford (Prior) on May 19, 2006 at 03:44 UTC
|
Children don't die automatically when their parent does. To kill them you'll have to, well, kill them: keep track of their PIDs, and kill them in an END block or $SIG{INT} handler.
| [reply] [d/l] [select] |
Re: Automatically killing a child
by bbfu (Curate) on May 19, 2006 at 04:26 UTC
|
If you have it, you can use pkill -g <GID> '.*' to kill the group of processes, I think.
bbfu
Black flowers blossom
Fearless on my breath
| [reply] [d/l] |
Re: Automatically killing a child
by ikegami (Patriarch) on May 19, 2006 at 02:20 UTC
|
I don't see any children. exec doesn't spawn children. exec executes a program in the current process. In other words, tail and the program that launches it are never running at the same time, because tail was launched via exec.
In fact, it looks like you executed your script twice. Once as process 7755, and once as process 7756.
Update: Nevermind. Apparently open -| returns the child pid. I don't see any mention of this in the docs. If open returned its usual status, exec would only get called when the pipe failed, and that's the scenerio I thought we had.
| [reply] [d/l] [select] |
|
| [reply] |
Re: Automatically killing a child
by roboticus (Chancellor) on May 19, 2006 at 13:05 UTC
|
Massyn:
I don't know what's going on, so this is pure speculation. But I think that tail is waiting until its input stream is closed. But with your script, tail's input stream is the terminal session's output stream (STDOUT). Thus, I think tail is waiting for your terminal session to close it's output stream before it exits.
Again, this is pure speculation....
--roboticus
| [reply] |
|
Hi everyone,
This was a real interesting topic, and ++ to all for your great contributions. In the end, I removed tail from the code, and just hard coded a simple perl based tail into my code. That works, plus I don't have to fork another process.
#!/usr/bin/perl
# Known issue
# If the file gets truncated, the script will not terminate
# ====================================================================
+=========
use IO::Handle;
autoflush STDOUT;
use Fcntl qw(:seek);
$file = 'mylog.txt';
$started = 0; #set to 1 if you want the file to start reading from
+the start of the logfile
while(1)
{
open LOG, $file or die "$file could not be opened.";
seek LOG, $pos, SEEK_SET if defined $pos;
while(<LOG>)
{
chomp;
if($started)
{
print "$_\n";
}
}
$pos = tell LOG;
close LOG;
sleep 1;
$started = 1;
}
exit(0);
Thanks!
|\/| _. _ _ ._
www. | |(_|_>_>\/| | .net
/
The more I learn the more I realise I don't know.
- Albert Einstein
| [reply] [d/l] |
|
|