I am using Linux
and .sh
is in tcsh
.
I have made a very basic fork and exec, but I need help in implementing safeties to it.
Basically my perl script calls a .sh
script in a child process. But when I do Ctrl+c
to kill the parent, the signal gets ignored by the child.
1) How do I capture the SIGINT
for the child process as well?
2) The child process that runs the .sh script still STDOUT to the screen of the xterm. How can I remove this? I was thinking of doing running the script in the background
exec("shell.sh args &");
But haven't tested as I need to figure out how to keep the child from going wild first.
3) The parent process(perl script) doesn't wait on the child(.sh script). So I've read a lot about the child becoming a zombie??? Will it happen after the script is done? And how would I stop it?
$pid = fork();
if($pid < 0){
print "Failed to fork process... Exiting";
exit(-1);
}
elsif ($pid ==0) {
#child process
exec("shell.sh args");
exit(1);
}
else { #execute rest of parent}
But when I do ctrl+c to kill the parent, the signal gets ignored by the child.
The signal is sent to two both the parent and the child.
$ perl -E'
if (my $pid = fork()) {
local $SIG{INT} = sub { say "Parent got SIGINT" };
sleep;
waitpid($pid, 0);
} else {
local $SIG{INT} = sub { say "Child got SIGINT" };
sleep;
}
'
^CParent got SIGINT
Child got SIGINT
If that child ignores it, it's because it started a new session or because it explicitly ignores it.
The child procces that runs the .sh script still STDOUT to the screen of the xterm. How can I remove this?
Do the following in the child before calling exec
:
open(STDOUT, '>', '/dev/null');
open(STDERR, '>', '/dev/null');
Actually, I would use open3
to get some error checking.
open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
open(local *CHILD_STDOUT, '>', '/dev/null') or die $!;
my $pid = open3(
'<&CHILD_STDIN',
'>&CHILD_STDOUT',
'>&CHILD_STDOUT',
'shell.sh', 'args',
);
The parent process(perl script) doesn't wait on the child(.sh script). So I've read alot about the child becoming a zombie???
Children are automatically reaped when the parent exits, or if they exit after the parent exits.
$ perl -e'
for (1..3) {
exec(perl => (-e => 1)) if !fork;
}
sleep 1;
system("ps");
' ; ps
PID TTY TIME CMD
26683 pts/13 00:00:00 bash
26775 pts/13 00:00:00 perl
26776 pts/13 00:00:00 perl <defunct> <-- zombie
26777 pts/13 00:00:00 perl <defunct> <-- zombie
26778 pts/13 00:00:00 perl <defunct> <-- zombie
26779 pts/13 00:00:00 ps
PID TTY TIME CMD
26683 pts/13 00:00:00 bash
26780 pts/13 00:00:00 ps
<-- all gone
If the parent exits before the children do, there's no problem.
If the parent exits shortly after the children do, there's no problem.
If the parent exits a long time after the children do, you'll want to reap them. You could do that using wait
or waitpid
(possibly from a SIGCHLD
handler), or you could cause them to be automatically reaped using $SIG{CHLD} = 'IGNORE';
. See perlipc.
Use waitpid in the parent thread: http://perldoc.perl.org/functions/waitpid.html
waitpid($pid, 0);
You can also redirect stdout of your exec to /dev/null:
exec("shell.sh args > /dev/null");