Perl Fork() Exec() , Child Process Gone Wild

perl fork() exec() , child process gone wild

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.

Perl Script, Fork/Exec, System claims my process has died when in fact only my child process has died

Just a sanity check, is your main program walking the right fork? It should follow the non-zero path:

my $pid = fork;
if ($pid == 0) {
print "Child\n";
} else {
print "Main\n";
}

From man fork:

Upon successful completion, fork()
returns a value of 0 to the child
process and returns the process ID of
the child process to the parent
process.

fork + exec + caller should not wait for child

Instead of using `` in script_a. We have redirected the STDOUT and STDERR in script_a.
Something like

script_a

system("script_b.pl > /var/tmp/out_file 2>&1");

script_b

#! /usr/local/bin/perl

$f_id = fork();

if (! $f_id) {
exec("sleep 10; echo 'i am child'");
}

if ($f_id) {
print "i am parent\n";
}

This way the caller didnot wait for the child in exec to complete.

Thanks for the help here.

Kill child process created with fork

When you fork a child, and then fail to wait() on it, it will become a defunct process (a zombie in Unix parlance) when it exits. You'll notice that its parent process ID becomes 1, and it will not go away until the OS rebooted.

So the traditional pseudocode for forking looks something like this:

if ($pid = fork()) {
# pid is non-zero, this is the parent
waitpid($pid) # tell OS that we care about the child

do other parental stuff
}
else {
# pid is 0 so this is the child process
do_childish_things()
}

Your code doesn't do that, so you're probably getting zombies, and then getting frustrated that you can't get rid of them.

how to kill process having multiple fork using perl

In a more complicated case, you can set the perl child process to be a session leader with POSIX::setsid(), and then send the signal to the process group by passing a negative value to kill.

if(!defined( my $pid = fork())) {
die "Cannot fork a child: $!";
} elsif ($pid == 0) {
POSIX::setsid(); # make this process a session leader
print "Printed by child process\n";
system("./program_that_forks"); exit; # or exec('./program_that_forks')

} else {
...
kill('KILL', -$pid); # -$pid means signal the whole process group
...
}

If the program_that_forks is also manipulating process groups, either by calling setsid(1) or by closing standard file descriptors and becoming a daemon, the convention is for the program to write its process id to a file, and for system task scripts to read this file to signal the program (run ls /var/run/*.pid to see some examples).

Perl fork exec, system in parent and kill child

I figured that the problem was to kill the all process tree and
That SO answer solves the problem

I had this to the child process

setpgrp(0, 0);

And change the kill instruction to

kill 9, -$pid;

Looks like this now

my $pid = fork();
die "unable to fork: $!" unless defined($pid);
if (!$pid) { # child
setpgrp(0, 0);
exec("tail -f $logfile | logger -t $ENV{SUDO_USER}:$target ");
die "unable to exec: $!";
}

$show_cmd && print "% $cmd\n" ;
system $cmd or die "exec() failed: $!\n" ;
printf "Session end pid to kill %d\n", $pid;
kill 9, -$pid;
waitpid $pid, 0;
printf "End of the script.\n";

Thanks for helping me



Related Topics



Leave a reply



Submit