views:

371

answers:

1

I have a Perl script that does a fork/exec to start another tool in the background and monitor some file system changes while this other tool is running. This seems to work like expected.

When I start this Perl script from a shell (e.g. Bash), of course the shell prompt should be gone for as long as my Perl script is running. And it will keep running until the expected file modification has taken place; but there is no guarantee that the file modification might be done by the external tool, in that case the external tool will exit, but my script will keep running and has to handle that situation somehow - this handling is beyond the scope of the question and not related to my problem (so far it is not even implemented).

My problem is that as soon as my child process dies, Bash returns to its prompt, claiming my process has finished running... which is not true. It clearly is still running in the background and it still waits for the file system modification. If I keep printing some text in the main loop of the script, this text is still printed, even though bash has returned back to the prompt already.

I cannot figure out what makes bash believe my process has quit. I tried blocking the SIGCHLD signal in my script, I tried closing and/or redirecting STDOUT/STDERR/STDIN (which are duplicated on fork, but you never know) - no success. I even tried the famous "double fork", to make the final child independent of my script process, same outcome. No matter what I do, as soon as my child (or grandchild) dies, Bash beliefs my process has quit. Starting my script in the background (using "&" at the end) makes Bash even tell me that process XYZ has finished (and it names my process here, not the child process, even though my process is happily alive and printing to terminal via STDOUT that very moment).

If this was only an issue of Bash, I couldn't care any less, but other third party software that is supposed to run my script acts the same way. As soon as my child dies, they claim that my script has in fact died, which is simply not true.

+1  A: 

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.

Andomar
Ummm... good point you have there... I will double check that in exactly 11 hours from now (this is when I will have access to my code again). This would really be a stupid mistake, but everyone makes stupid mistakes once in a while and if it was doing the exec in the wrong fork, this would indeed match the undesired behavior described above.
Mecki
You are right - printing some debug output right before the exec shows that the exec runs in the parent and not in the child - DOOHH! Stupid mistake!!!
Mecki