PHP: proc_get_status exitcode is always -1 after pcntl_fork

150 views Asked by At

I'm having troubles with using proc_get_status after a pcntl_fork in the parent process.

Here's an example with docker and PHP 7.4, but note the PHP version does not matter, the result is the same from at least PHP 7.2 to PHP 8.1.

Setup

Dockerfile

FROM php:7.4
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions pcntl

Run: docker build -t php-pcntl-7.4 .

test.php

<?php

if ($argv[1] ?? false) {
    pcntl_async_signals(true);
    pcntl_signal(SIGCHLD, SIG_IGN);
    $pid = pcntl_fork();
    if ($pid === -1) {
        throw new \RuntimeException('fork failed');
    }

    if ($pid === 0) {
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
        throw new \Exception('child should be ignored');
    }
    pcntl_waitpid($pid, $childStatusCode);
}

function runCommand(string $command): void
{
    $pipes = [];
    $proc = proc_open($command, [['pipe', 'r'],['pipe', 'w'],['pipe', 'w']], $pipes);
    do {
        if (isset($status)) {
            usleep(300000);
        }

        $status = proc_get_status($proc);
    } while ($status['running']);
    echo 'Command: ' . $command . PHP_EOL;
    echo 'last proc_get_status exitcode: ' . $status['exitcode'] . PHP_EOL;
    echo PHP_EOL;
}

echo 'PHP version: ' . PHP_VERSION . PHP_EOL;
runCommand('/bin/echo test');
runCommand('/bin/false');

Test without running a fork before

Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php

Output:

PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: 0

Command: /bin/false
last proc_get_status exitcode: 1

Test with running a fork before

Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php 1

Output:

PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: -1

Command: /bin/false
last proc_get_status exitcode: -1

Does anyone have an idea of why the exitcode is always -1, and if there is a workaround ?

1

There are 1 answers

0
Steve Campbell On

This seems to be a bug in the pcntl_signal(SIGCHLD, SIG_IGN) call. Remove the call and the problem goes away.

As SIG_IGN is the default for SIGCHLD, it's rarely needed which is probably why this hasn't been noticed before.