Search code examples
perlshellbackgrounding

Perl on background when invoked from another env


I have a Perl script that is supposed to do some work on background. This is well described - I fork, kill (return 0) the parent and do the work in the child. When I run it directly from shell, it works as expected (i.e. returns to shell right after killing the parent and continues on background). But if I run it from another environment, e.g. from PHP via executing

    php -r "passthru('my-perl-script.pl')"

it returns to shell after the child is done. Any ideas why is this happening?

Thanks!

EDIT: Here is the Perl code I was using:

#!/usr/bin/env perl
use strict;
use warnings;

local $| = 1;

# fork the process - returns child pid to the parent process and 0
# to the child process
print ' [FORKING] ';
my $pid = fork();
error('Failed to fork: $@') and exit 1 if $@;

# exit parent
print ' [KILLING PARENT] ';
exit 0 if $pid;

# continue as child process
print " [CONTINUING AS CHILD] \n";

# wait 3 secs (for testing) and exit
sleep 3;
print " [DONE]\n";
exit 1;

Output when executed directly:

$ ./background-test.pl
 [FORKING]  [KILLING PARENT]  [KILLING PARENT]  [CONTINUING AS CHILD]
$  [DONE] 

Output when executed via PHP:

$ php -r "system('./background-test.pl');"
$ [FORKING]  [KILLING PARENT]  [KILLING PARENT]  [CONTINUING AS CHILD]
  # ... 3 seconds wait ... 
  [DONE]
$

My question was why doesn't the Perl script disconnect when invoked from other environments (here PHP is just an example).

Thanks!


Solution

  • If I understand correctly, you're saying that PHP is waiting for the grandchild to end even though the child exited.

    system doesn't return since php collects the child's STDOUT, the same STDOUT that was inherited by the grandchild. On a Linux system, this can be seen by adding the following to the Perl script:

    system("ls -l /proc/$$/fd");
    

    From shell:

    lrwx------ 1 ikegami ikegami 64 Jun  1 14:07 1 -> /dev/pts/0
    

    From PHP:

    l-wx------ 1 ikegami ikegami 64 Jun  1 14:08 1 -> pipe:[10052926]
    

    Normally, when you deamonize a process, you reopen its STDIN, STDOUT and STDERR, redirecting them to /dev/null or to a log file.

    open(STDIN,  '<',  '/dev/null') or die $!;
    open(STDOUT, '>',  '/dev/null') or die $!;
    open(STDERR, '>>', '/var/log/application.log') or die $!;
    

    Normally, when you deamonize a process, you also call POSIX::setsid().