i started a child process with proc_open(), and now i need to wait until the child has finished -or- until X seconds has passed, whichever comes first. one obvious way to solve that problem is a while() loop that checks on every iteration like this:
$starttime = microtime(true);
$unused = [];
$ph = proc_open($cmd, $unused, $unused);
$terminated = false; // < protection against running pkilltree() twice
// OPTIMIZE ME: use stream_select() or something instead of sleep-loop
while (($status = proc_get_status($ph))['running']) {
usleep(100 * 1000); // *1000 = ms
if (! $terminated && microtime(true) - $starttime > MAX_RUNTIME_SECONDS) {
$terminated = true;
echo 'max runtime reached (' . MAX_RUNTIME_SECONDS . ' seconds), terminating...';
pkilltree((int) ($status['pid']));
// proc_terminate ( $ph, SIGKILL );
}
}
however if the process finish in 1 millisecond, then waiting 99 milliseconds for the sleep() is (relatively) much time wasted, otoh i could just check every 1 millisecond instead of every 100, but that would waste a lot of cpu. with linux api one could probably use sigtimedwait() to wait for SIGCHLD, but in PHP i suspect (but haven't properly verified) that the PHP interpreter itself intercepts and hides SIGCHLD from userland php code, so.. any suggestions?
I'm just curious, is it necessary to use proc_open()? Because as your example code it is possible to do it with exec() function but it need a simple CLI tool to use with, its timeout
.
timeout - run a command with a time limit Start COMMAND, and kill it if still running after DURATION
So this code is alternative for your code, unless you want to do something else with the child.
$starttime = microtime(true);
exec("timeout " . MAX_RUNTIME_SECONDS . " $cmd");
$terminated = false;
if (! $terminated && microtime(true) - $starttime > MAX_RUNTIME_SECONDS) {
$terminated = true;
echo 'max runtime reached (' . MAX_RUNTIME_SECONDS . ' seconds), terminating...';
}
This trick I've been using for years with multiprocessing in PHP. And its work perfectly for me.