[Process] Refactor the windows handling so it is always executed
When regular pipes are closed, the file handlers fallback on windows should still be processed until they are empty
This commit is contained in:
parent
0c5aa8bf7e
commit
bcf8cf9116
@ -206,6 +206,9 @@ class Process
|
|||||||
$this->fileHandles = array(
|
$this->fileHandles = array(
|
||||||
self::STDOUT => tmpfile(),
|
self::STDOUT => tmpfile(),
|
||||||
);
|
);
|
||||||
|
$this->readBytes = array(
|
||||||
|
self::STDOUT => 0,
|
||||||
|
);
|
||||||
$descriptors = array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w'));
|
$descriptors = array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w'));
|
||||||
} else {
|
} else {
|
||||||
$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
|
$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
|
||||||
@ -236,14 +239,18 @@ class Process
|
|||||||
unset($this->pipes[0]);
|
unset($this->pipes[0]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
$writePipes = array($this->pipes[0]);
|
|
||||||
unset($this->pipes[0]);
|
|
||||||
$stdinLen = strlen($this->stdin);
|
|
||||||
$stdinOffset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$writePipes = array($this->pipes[0]);
|
||||||
|
unset($this->pipes[0]);
|
||||||
|
$stdinLen = strlen($this->stdin);
|
||||||
|
$stdinOffset = 0;
|
||||||
|
|
||||||
while ($writePipes) {
|
while ($writePipes) {
|
||||||
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
|
$this->processFileHandles($callback);
|
||||||
|
}
|
||||||
|
|
||||||
$r = $this->pipes;
|
$r = $this->pipes;
|
||||||
$w = $writePipes;
|
$w = $writePipes;
|
||||||
$e = null;
|
$e = null;
|
||||||
@ -252,7 +259,8 @@ class Process
|
|||||||
|
|
||||||
if (false === $n) {
|
if (false === $n) {
|
||||||
break;
|
break;
|
||||||
} elseif ($n === 0) {
|
}
|
||||||
|
if ($n === 0) {
|
||||||
proc_terminate($this->process);
|
proc_terminate($this->process);
|
||||||
|
|
||||||
throw new \RuntimeException('The process timed out.');
|
throw new \RuntimeException('The process timed out.');
|
||||||
@ -269,22 +277,6 @@ class Process
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
|
||||||
$fh = $this->fileHandles;
|
|
||||||
foreach ($fh as $type => $fileHandle) {
|
|
||||||
fseek($fileHandle, 0);
|
|
||||||
$data = fread($fileHandle, 8192);
|
|
||||||
$this->readBytes[$type] = strlen($data);
|
|
||||||
if (strlen($data) > 0) {
|
|
||||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
|
||||||
}
|
|
||||||
if (false === $data) {
|
|
||||||
fclose($fileHandle);
|
|
||||||
unset($this->fileHandles[$type]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($r as $pipe) {
|
foreach ($r as $pipe) {
|
||||||
$type = array_search($pipe, $this->pipes);
|
$type = array_search($pipe, $this->pipes);
|
||||||
$data = fread($pipe, 8192);
|
$data = fread($pipe, 8192);
|
||||||
@ -319,53 +311,40 @@ class Process
|
|||||||
$this->processInformation = proc_get_status($this->process);
|
$this->processInformation = proc_get_status($this->process);
|
||||||
$callback = $this->buildCallback($callback);
|
$callback = $this->buildCallback($callback);
|
||||||
while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) {
|
while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) {
|
||||||
$r = $this->pipes;
|
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
|
||||||
$w = null;
|
$this->processFileHandles($callback, !$this->pipes);
|
||||||
$e = null;
|
|
||||||
|
|
||||||
$n = @stream_select($r, $w, $e, $this->timeout);
|
|
||||||
|
|
||||||
if (false === $n) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (0 === $n) {
|
|
||||||
proc_terminate($this->process);
|
|
||||||
|
|
||||||
throw new \RuntimeException('The process timed out.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
if ($this->pipes) {
|
||||||
$fh = $this->fileHandles;
|
$r = $this->pipes;
|
||||||
foreach ($fh as $type => $fileHandle) {
|
$w = null;
|
||||||
fseek($fileHandle, $this->readBytes[$type]);
|
$e = null;
|
||||||
$data = fread($fileHandle, 8192);
|
|
||||||
if (isset($this->readBytes)) {
|
|
||||||
$this->readBytes[$type] += strlen($data);
|
|
||||||
} else {
|
|
||||||
$this->readBytes[$type] = strlen($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$n = @stream_select($r, $w, $e, $this->timeout);
|
||||||
|
|
||||||
|
if (false === $n) {
|
||||||
|
$this->pipes = array();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 === $n) {
|
||||||
|
proc_terminate($this->process);
|
||||||
|
|
||||||
|
throw new \RuntimeException('The process timed out.');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($r as $pipe) {
|
||||||
|
$type = array_search($pipe, $this->pipes);
|
||||||
|
$data = fread($pipe, 8192);
|
||||||
if (strlen($data) > 0) {
|
if (strlen($data) > 0) {
|
||||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||||
}
|
}
|
||||||
if (false === $data) {
|
if (false === $data || feof($pipe)) {
|
||||||
fclose($fileHandle);
|
fclose($pipe);
|
||||||
unset($this->fileHandles[$type]);
|
unset($this->pipes[$type]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($r as $pipe) {
|
|
||||||
$type = array_search($pipe, $this->pipes);
|
|
||||||
$data = fread($pipe, 8192);
|
|
||||||
if (strlen($data) > 0) {
|
|
||||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
|
||||||
}
|
|
||||||
if (false === $data || feof($pipe)) {
|
|
||||||
fclose($pipe);
|
|
||||||
unset($this->pipes[$type]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$this->updateStatus();
|
$this->updateStatus();
|
||||||
if ($this->processInformation['signaled']) {
|
if ($this->processInformation['signaled']) {
|
||||||
@ -725,4 +704,27 @@ class Process
|
|||||||
$this->addOutput(stream_get_contents($this->pipes[self::STDOUT]));
|
$this->addOutput(stream_get_contents($this->pipes[self::STDOUT]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the windows file handles fallbacks
|
||||||
|
*
|
||||||
|
* @param mixed $callback A valid PHP callback
|
||||||
|
* @param Boolean $closeEmptyHandles if true, handles that are empty will be assumed closed
|
||||||
|
*/
|
||||||
|
private function processFileHandles($callback, $closeEmptyHandles = false)
|
||||||
|
{
|
||||||
|
$fh = $this->fileHandles;
|
||||||
|
foreach ($fh as $type => $fileHandle) {
|
||||||
|
fseek($fileHandle, $this->readBytes[$type]);
|
||||||
|
$data = fread($fileHandle, 8192);
|
||||||
|
if (strlen($data) > 0) {
|
||||||
|
$this->readBytes[$type] += strlen($data);
|
||||||
|
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||||
|
}
|
||||||
|
if (false === $data || ($closeEmptyHandles && '' === $data && feof($fileHandle))) {
|
||||||
|
fclose($fileHandle);
|
||||||
|
unset($this->fileHandles[$type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user