Skip to content

Commit

Permalink
merged branch romainneutron/fix-8742 (PR #8744)
Browse files Browse the repository at this point in the history
This PR was merged into the 2.3 branch.

Discussion
----------

[Process] Fix #8742 : Signal-terminated processes are not successful

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | require #8741 to be merged to pass tests
| Fixed tickets | #8742
| License       | MIT

Commits
-------

909fab6 [Process] Fix #8742 : Signal-terminated processes are not successful
  • Loading branch information
fabpot committed Aug 14, 2013
2 parents 16413ff + 909fab6 commit 4af7276
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 25 deletions.
77 changes: 52 additions & 25 deletions src/Symfony/Component/Process/Process.php
Expand Up @@ -332,8 +332,6 @@ public function wait($callback = null)
usleep(1000);
}

$exitcode = proc_close($this->process);

if ($this->processInformation['signaled']) {
if ($this->isSigchildEnabled()) {
throw new RuntimeException('The process has been signaled.');
Expand All @@ -342,12 +340,6 @@ public function wait($callback = null)
throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
}

$this->exitcode = $this->processInformation['running'] ? $exitcode : $this->processInformation['exitcode'];

if (-1 == $this->exitcode && null !== $this->fallbackExitcode) {
$this->exitcode = $this->fallbackExitcode;
}

return $this->exitcode;
}

Expand Down Expand Up @@ -664,20 +656,7 @@ public function stop($timeout = 10, $signal = null)
}
}

foreach ($this->pipes as $pipe) {
fclose($pipe);
}
$this->pipes = array();

$exitcode = proc_close($this->process);
$this->exitcode = -1 === $this->processInformation['exitcode'] ? $exitcode : $this->processInformation['exitcode'];

if (defined('PHP_WINDOWS_VERSION_BUILD')) {
foreach ($this->fileHandles as $fileHandle) {
fclose($fileHandle);
}
$this->fileHandles = array();
}
$this->updateStatus(false);
}
$this->status = self::STATUS_TERMINATED;

Expand Down Expand Up @@ -1070,11 +1049,10 @@ protected function updateStatus($blocking)
$this->readPipes($blocking);

$this->processInformation = proc_get_status($this->process);
$this->captureExitCode();
if (!$this->processInformation['running']) {
$this->close();
$this->status = self::STATUS_TERMINATED;
if (-1 !== $this->processInformation['exitcode']) {
$this->exitcode = $this->processInformation['exitcode'];
}
}
}

Expand Down Expand Up @@ -1253,4 +1231,53 @@ private function processReadPipes(array $pipes)
}
}
}

/**
* Captures the exitcode if mentioned in the process informations.
*/
private function captureExitCode()
{
if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {
$this->exitcode = $this->processInformation['exitcode'];
}
}


/**
* Closes process resource, closes file handles, sets the exitcode.
*
* @return Integer The exitcode
*/
private function close()
{
foreach ($this->pipes as $pipe) {
fclose($pipe);
}

$this->pipes = null;
$exitcode = -1;

if (is_resource($this->process)) {
$exitcode = proc_close($this->process);
}

$this->exitcode = $this->exitcode !== null ? $this->exitcode : -1;
$this->exitcode = -1 != $exitcode ? $exitcode : $this->exitcode;

if (-1 == $this->exitcode && null !== $this->fallbackExitcode) {
$this->exitcode = $this->fallbackExitcode;
} elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
// if process has been signaled, no exitcode but a valid termsig, apply unix convention
$this->exitcode = 128 + $this->processInformation['termsig'];
}

if (defined('PHP_WINDOWS_VERSION_BUILD')) {
foreach ($this->fileHandles as $fileHandle) {
fclose($fileHandle);
}
$this->fileHandles = array();
}

return $this->exitcode;
}
}
18 changes: 18 additions & 0 deletions src/Symfony/Component/Process/Tests/AbstractProcessTest.php
Expand Up @@ -483,6 +483,24 @@ public function testSignal()
$this->assertEquals('Caught SIGUSR1', $process->getOutput());
}

public function testExitCodeIsAvailableAfterSignal()
{
$this->verifyPosixIsEnabled();

$process = $this->getProcess('sleep 4');
$process->start();
$process->signal(SIGKILL);

while ($process->isRunning()) {
usleep(10000);
}

$this->assertFalse($process->isRunning());
$this->assertTrue($process->hasBeenSignaled());
$this->assertFalse($process->isSuccessful());
$this->assertEquals(137, $process->getExitCode());
}

/**
* @expectedException Symfony\Component\Process\Exception\LogicException
*/
Expand Down
Expand Up @@ -138,6 +138,11 @@ public function testProcessThrowsExceptionWhenExternallySignaled()
$this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
}

public function testExitCodeIsAvailableAfterSignal()
{
$this->markTestSkipped('Signal is not supported in sigchild environment');
}

/**
* {@inheritdoc}
*/
Expand Down
Expand Up @@ -98,6 +98,11 @@ public function testProcessThrowsExceptionWhenExternallySignaled()
$this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
}

public function testExitCodeIsAvailableAfterSignal()
{
$this->markTestSkipped('Signal is not supported in sigchild environment');
}

/**
* {@inheritdoc}
*/
Expand Down

0 comments on commit 4af7276

Please sign in to comment.