From bcf8cf911632776e9e809ae460485716808c808f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 24 May 2012 19:53:48 +0200 Subject: [PATCH] [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 --- src/Symfony/Component/Process/Process.php | 122 +++++++++++----------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 23e2e89e41..bea18550ae 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -206,6 +206,9 @@ class Process $this->fileHandles = array( self::STDOUT => tmpfile(), ); + $this->readBytes = array( + self::STDOUT => 0, + ); $descriptors = array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w')); } else { $descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')); @@ -236,14 +239,18 @@ class Process unset($this->pipes[0]); 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) { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->processFileHandles($callback); + } + $r = $this->pipes; $w = $writePipes; $e = null; @@ -252,7 +259,8 @@ class Process if (false === $n) { break; - } elseif ($n === 0) { + } + if ($n === 0) { proc_terminate($this->process); 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) { $type = array_search($pipe, $this->pipes); $data = fread($pipe, 8192); @@ -319,53 +311,40 @@ class Process $this->processInformation = proc_get_status($this->process); $callback = $this->buildCallback($callback); while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) { - $r = $this->pipes; - $w = null; - $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') && $this->fileHandles) { + $this->processFileHandles($callback, !$this->pipes); } - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $fh = $this->fileHandles; - foreach ($fh as $type => $fileHandle) { - fseek($fileHandle, $this->readBytes[$type]); - $data = fread($fileHandle, 8192); - if (isset($this->readBytes)) { - $this->readBytes[$type] += strlen($data); - } else { - $this->readBytes[$type] = strlen($data); - } + if ($this->pipes) { + $r = $this->pipes; + $w = null; + $e = null; + $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) { call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data); } - if (false === $data) { - fclose($fileHandle); - unset($this->fileHandles[$type]); + if (false === $data || feof($pipe)) { + fclose($pipe); + 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(); if ($this->processInformation['signaled']) { @@ -725,4 +704,27 @@ class Process $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]); + } + } + } }