简体   繁体   中英

PHP prevent SIGTERM to bubble to proc_open process

Original question (Send SIGTERM to child on CTRL+C and parent should wait for it to close). See update below!

I have a PHP script (see below) starting a process and tailing it's output. This process keeps running until I ask PHP to stop by hitting CTRL+C or sending a SIGTERM signal to the PHP scripts (pid). At this point PHP decides to kill the process started by proc_open immediately instead of closing it gracefully and waiting on it before closing itself, how can I achieve this?

I tried a few things like adding pcntl_waitpid($childPid) etc, but so far obviously no luck.

<?php

// Handle close signals (like CTRL+C).
function closeChildApplication(int $signal) {
    // ???
}

// Async signals instead of declare(TICKS=1) PHP 7.1+
pcntl_async_signals(true);
pcntl_signal(SIGTERM, 'closeChildApplication', false);
pcntl_signal(SIGINT, 'closeChildApplication', false);

// Create process.
$descriptors = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe', 'w']
];
$proc = proc_open('<command-to-run>', $descriptors, $pipes);
if (!is_resource($proc)) {
    throw new \RuntimeException('Could not execute <command-to-run>.');
}

// Not sending any data to child, so close STDIN immediately.
fclose($pipes[0]);

// Non blocking mode.
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);

do {
    $status = proc_get_status($proc);

    $data = '';
    while (!feof($pipes[1]) && false !== ($line = fgets($pipes[1]))) {
        $data .= $line;
    }
    if (!empty(trim($data))) {
        // STDOUT logic here.
    }

    $data = '';
    while (!feof($pipes[2]) && false !== ($line = fgets($pipes[2]))) {
        $data .= $line;
    }
    if (!empty(trim($data))) {
        // STDERR logic here.
    }

    sleep(1);
} while ($status['running']);

// Not running anymore, close resource.
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($proc);

UPDATE It seems PHP is waiting for child to be closed but the program in question is not handling the SIGTERM and SIGINT very well and kills itself immediately instead of cleaning up and closing. I found out that I can send QUIT command to the programs STDIN to trigger a clean shutdown.

But the problem I now face is that when PHP receives a SIGTERM/SIGINT signal this is also send to program opened with proc_open (so it bubbles down to the child).

By playing around a bit if found out we can do pcntl_signal(SIGTERM, SIG_IGN, false); which causes PHP to ignore the signal and prevents it from being send to the child. But now I don't know if a signal is send.

Another way is to do:

function closeChildApplication(int $signal) {
    // do nothing in here.
}

pcntl_signal(SIGTERM, 'closeChildApplication', false);

In which case PHP ignores the signal and keeps running but the child receives it and is killed. Anyone who knows how to prevent a signal to bubble to child or ignore the signals but for example in below while to check if any signals are received?

So after a few days of puzzling around with this issue if found out that proc_open seems to sort of inherit PHP's setting regarding the SIG_IGN signal.

When saying pcntl_signal(SIGTERM, SIG_IGN, false); PHP and process opened by proc_open both ignore this signal.

When saying pcntl_signal(SIGTERM, function(){ echo 'test'; }, false); PHP echoes 'test' and continues to run, however the process opened by proc_open is also receiving SIGTERM and closes itself.

But interestingly when I do:

// Ignore all signals:
pcntl_signal(SIGTERM, SIG_IGN, false);

// Start program:
proc_open('command // etc');

// Install signal handler for PHP:
pcntl_signal(SIGTERM, function(){ echo 'test'; }, false);

PHP echoes 'test' on receiving the signal, but the process started with proc_open is not doing anything with the SIGTERM signal which indicates to me that SIG_IGN is inherited by proc_open.

This is exactly what I need right now, but is kinda weird that this is the only way to tell proc_open to ignore some signals, not sure if this is intended behavior or a PHP bug.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM