PHP:pcntl_fork 之后 proc_get_status 退出代码始终为 -1

发布于 2025-01-11 17:07:51 字数 2181 浏览 0 评论 0原文

我在父进程中的 pcntl_fork 之后使用 proc_get_status 时遇到问题。

这是一个使用 docker 和 PHP 7.4 的示例,但请注意 PHP 版本并不重要,至少从 PHP 7.2 到 PHP 8.1 结果是相同的。

设置

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

运行: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');

测试之前不运行 fork

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

输出:

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

Command: /bin/false
last proc_get_status exitcode: 1

在之前运行 fork 进行测试

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

输出:

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

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

有谁知道为什么退出代码总是-1,以及是否有解决方法?

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

⒈起吃苦の倖褔 2025-01-18 17:07:53

这似乎是 pcntl_signal(SIGCHLD, SIG_IGN) 调用中的错误。删除呼叫,问题就消失了。

由于 SIG_IGN 是 SIGCHLD 的默认值,因此很少需要它,这可能就是为什么以前没有注意到这一点。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文