Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5ed2737

Browse files
romainneutronfabpot
authored andcommitted
[Process] Add signal and getPid methods
1 parent 6f0a5ad commit 5ed2737

File tree

6 files changed

+281
-8
lines changed

6 files changed

+281
-8
lines changed

src/Symfony/Component/Process/Process.php

+52-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Process;
1313

1414
use Symfony\Component\Process\Exception\InvalidArgumentException;
15+
use Symfony\Component\Process\Exception\LogicException;
1516
use Symfony\Component\Process\Exception\RuntimeException;
1617

1718
/**
@@ -467,6 +468,51 @@ public function wait($callback = null)
467468
return $this->exitcode;
468469
}
469470

471+
/**
472+
* Returns the Pid (process identifier), if applicable.
473+
*
474+
* @return integer|null The process id if running, null otherwise
475+
*
476+
* @throws RuntimeException In case --enable-sigchild is activated
477+
*/
478+
public function getPid()
479+
{
480+
if ($this->isSigchildEnabled()) {
481+
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.');
482+
}
483+
484+
$this->updateStatus();
485+
486+
return $this->isRunning() ? $this->processInformation['pid'] : null;
487+
}
488+
489+
/**
490+
* Sends a posix signal to the process.
491+
*
492+
* @param integer $signal A valid posix signal (see http://www.php.net/manual/en/pcntl.constants.php)
493+
* @return Process
494+
*
495+
* @throws LogicException In case the process is not running
496+
* @throws RuntimeException In case --enable-sigchild is activated
497+
* @throws RuntimeException In case of failure
498+
*/
499+
public function signal($signal)
500+
{
501+
if (!$this->isRunning()) {
502+
throw new LogicException('Can not send signal on a non running process.');
503+
}
504+
505+
if ($this->isSigchildEnabled()) {
506+
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
507+
}
508+
509+
if (true !== @proc_terminate($this->process, $signal)) {
510+
throw new RuntimeException(sprintf('Error while sending signal `%d`.', $signal));
511+
}
512+
513+
return $this;
514+
}
515+
470516
/**
471517
* Returns the current output of the process (STDOUT).
472518
*
@@ -714,12 +760,13 @@ public function getStatus()
714760
* Stops the process.
715761
*
716762
* @param integer|float $timeout The timeout in seconds
763+
* @param integer $signal A posix signal to send in case the process has not stop at timeout, default is SIGKILL
717764
*
718765
* @return integer The exit-code of the process
719766
*
720767
* @throws RuntimeException if the process got signaled
721768
*/
722-
public function stop($timeout = 10)
769+
public function stop($timeout = 10, $signal = null)
723770
{
724771
$timeoutMicro = (int) $timeout*1E6;
725772
if ($this->isRunning()) {
@@ -730,8 +777,10 @@ public function stop($timeout = 10)
730777
usleep(1000);
731778
}
732779

733-
if (!defined('PHP_WINDOWS_VERSION_BUILD') && $this->isRunning()) {
734-
proc_terminate($this->process, SIGKILL);
780+
if ($this->isRunning() && !$this->isSigchildEnabled()) {
781+
if (null !== $signal || defined('SIGKILL')) {
782+
$this->signal($signal ?: SIGKILL);
783+
}
735784
}
736785

737786
foreach ($this->pipes as $pipe) {

src/Symfony/Component/Process/Tests/AbstractProcessTest.php

+77-5
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ public function testStopWithTimeoutIsActuallyWorking()
5050
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
5151
$this->markTestSkipped('Stop with timeout does not work on windows, it requires posix signals');
5252
}
53-
if (!function_exists('pcntl_signal')) {
54-
$this->markTestSkipped('This test require pcntl_signal function');
55-
}
5653

5754
// exec is mandatory here since we send a signal to the process
5855
// see https://github.com/symfony/symfony/issues/5030 about prepending
@@ -61,7 +58,7 @@ public function testStopWithTimeoutIsActuallyWorking()
6158
$p->start();
6259
usleep(100000);
6360
$start = microtime(true);
64-
$p->stop(1.1);
61+
$p->stop(1.1, SIGKILL);
6562
while ($p->isRunning()) {
6663
usleep(1000);
6764
}
@@ -224,7 +221,7 @@ public function testGetExitCode()
224221

225222
public function testStatus()
226223
{
227-
$process = $this->getProcess('php -r "sleep(1);"');
224+
$process = $this->getProcess('php -r "usleep(500000);"');
228225
$this->assertFalse($process->isRunning());
229226
$this->assertFalse($process->isStarted());
230227
$this->assertFalse($process->isTerminated());
@@ -277,6 +274,17 @@ public function testProcessIsNotSignaled()
277274
$this->assertFalse($process->hasBeenSignaled());
278275
}
279276

277+
public function testProcessWithoutTermSignalIsNotSignaled()
278+
{
279+
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
280+
$this->markTestSkipped('Windows does not support POSIX signals');
281+
}
282+
283+
$process = $this->getProcess('php -m');
284+
$process->run();
285+
$this->assertFalse($process->hasBeenSignaled());
286+
}
287+
280288
public function testProcessWithoutTermSignal()
281289
{
282290
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
@@ -387,6 +395,70 @@ public function testCheckTimeoutOnStartedProcess()
387395
$this->assertLessThan($timeout + $precision, $duration);
388396
}
389397

398+
public function testGetPid()
399+
{
400+
$process = $this->getProcess('php -r "sleep(1);"');
401+
$process->start();
402+
$this->assertGreaterThan(0, $process->getPid());
403+
$process->stop();
404+
}
405+
406+
public function testGetPidIsNullBeforeStart()
407+
{
408+
$process = $this->getProcess('php -r "sleep(1);"');
409+
$this->assertNull($process->getPid());
410+
}
411+
412+
public function testGetPidIsNullAfterRun()
413+
{
414+
$process = $this->getProcess('php -m');
415+
$process->run();
416+
$this->assertNull($process->getPid());
417+
}
418+
419+
public function testSignal()
420+
{
421+
$process = $this->getProcess('exec php -f ' . __DIR__ . '/SignalListener.php');
422+
$process->start();
423+
usleep(500000);
424+
$process->signal(SIGUSR1);
425+
426+
while ($process->isRunning() && false === strpos($process->getoutput(), 'Caught SIGUSR1')) {
427+
usleep(10000);
428+
}
429+
430+
$this->assertEquals('Caught SIGUSR1', $process->getOutput());
431+
}
432+
433+
/**
434+
* @expectedException Symfony\Component\Process\Exception\LogicException
435+
*/
436+
public function testSignalProcessNotRunning()
437+
{
438+
$process = $this->getProcess('php -m');
439+
$process->signal(SIGHUP);
440+
}
441+
442+
/**
443+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
444+
*/
445+
public function testSignalWithWrongIntSignal()
446+
{
447+
$process = $this->getProcess('php -r "sleep(3);"');
448+
$process->start();
449+
$process->signal(-4);
450+
}
451+
452+
/**
453+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
454+
*/
455+
public function testSignalWithWrongNonIntSignal()
456+
{
457+
$process = $this->getProcess('php -r "sleep(3);"');
458+
$process->start();
459+
$process->signal('Céphalopodes');
460+
}
461+
390462
public function responsesCodeProvider()
391463
{
392464
return array(

src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php

+45
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,30 @@ public function testProcessWithoutTermSignal()
6464
/**
6565
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
6666
*/
67+
public function testGetPid()
68+
{
69+
parent::testGetPid();
70+
}
71+
72+
/**
73+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
74+
*/
75+
public function testGetPidIsNullBeforeStart()
76+
{
77+
parent::testGetPidIsNullBeforeStart();
78+
}
79+
80+
/**
81+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
82+
*/
83+
public function testGetPidIsNullAfterRun()
84+
{
85+
parent::testGetPidIsNullAfterRun();
86+
}
87+
88+
/**
89+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
90+
*/
6791
public function testExitCodeText()
6892
{
6993
$process = $this->getProcess('qdfsmfkqsdfmqmsd');
@@ -88,6 +112,27 @@ public function testIsNotSuccessful()
88112
parent::testIsNotSuccessful();
89113
}
90114

115+
/**
116+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
117+
*/
118+
public function testSignal()
119+
{
120+
parent::testSignal();
121+
}
122+
123+
/**
124+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
125+
*/
126+
public function testProcessWithoutTermSignalIsNotSignaled()
127+
{
128+
parent::testProcessWithoutTermSignalIsNotSignaled();
129+
}
130+
131+
public function testStopWithTimeoutIsActuallyWorking()
132+
{
133+
$this->markTestSkipped('Stopping with signal is not supported in sigchild environment');
134+
}
135+
91136
/**
92137
* {@inheritdoc}
93138
*/

src/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php

+40
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,30 @@ public function testProcessWithoutTermSignal()
4545
parent::testProcessWithoutTermSignal();
4646
}
4747

48+
/**
49+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
50+
*/
51+
public function testGetPid()
52+
{
53+
parent::testGetPid();
54+
}
55+
56+
/**
57+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
58+
*/
59+
public function testGetPidIsNullBeforeStart()
60+
{
61+
parent::testGetPidIsNullBeforeStart();
62+
}
63+
64+
/**
65+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
66+
*/
67+
public function testGetPidIsNullAfterRun()
68+
{
69+
parent::testGetPidIsNullAfterRun();
70+
}
71+
4872
public function testExitCodeText()
4973
{
5074
$process = $this->getProcess('qdfsmfkqsdfmqmsd');
@@ -53,6 +77,22 @@ public function testExitCodeText()
5377
$this->assertInternalType('string', $process->getExitCodeText());
5478
}
5579

80+
/**
81+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
82+
*/
83+
public function testSignal()
84+
{
85+
parent::testSignal();
86+
}
87+
88+
/**
89+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
90+
*/
91+
public function testProcessWithoutTermSignalIsNotSignaled()
92+
{
93+
parent::testProcessWithoutTermSignalIsNotSignaled();
94+
}
95+
5696
/**
5797
* {@inheritdoc}
5898
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
// required for signal handling
4+
declare(ticks = 1);
5+
6+
pcntl_signal(SIGUSR1, function(){echo "Caught SIGUSR1"; exit;});
7+
8+
$n=0;
9+
10+
// ticks require activity to work - sleep(4); does not work
11+
while($n < 400) {
12+
usleep(10000);
13+
$n++;
14+
}
15+
16+
return;

src/Symfony/Component/Process/Tests/SimpleProcessTest.php

+51
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,57 @@ public function testIsNotSuccessful()
7979
parent::testIsNotSuccessful();
8080
}
8181

82+
public function testGetPid()
83+
{
84+
$this->skipIfPHPSigchild();
85+
parent::testGetPid();
86+
}
87+
88+
public function testGetPidIsNullBeforeStart()
89+
{
90+
$this->skipIfPHPSigchild();
91+
parent::testGetPidIsNullBeforeStart();
92+
}
93+
94+
public function testGetPidIsNullAfterRun()
95+
{
96+
$this->skipIfPHPSigchild();
97+
parent::testGetPidIsNullAfterRun();
98+
}
99+
100+
public function testSignal()
101+
{
102+
$this->skipIfPHPSigchild();
103+
parent::testSignal();
104+
}
105+
106+
/**
107+
* @expectedException Symfony\Component\Process\Exception\LogicException
108+
*/
109+
public function testSignalProcessNotRunning()
110+
{
111+
$this->skipIfPHPSigchild();
112+
parent::testSignalProcessNotRunning();
113+
}
114+
115+
/**
116+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
117+
*/
118+
public function testSignalWithWrongIntSignal()
119+
{
120+
$this->skipIfPHPSigchild();
121+
parent::testSignalWithWrongIntSignal();
122+
}
123+
124+
/**
125+
* @expectedException Symfony\Component\Process\Exception\RuntimeException
126+
*/
127+
public function testSignalWithWrongNonIntSignal()
128+
{
129+
$this->skipIfPHPSigchild();
130+
parent::testSignalWithWrongNonIntSignal();
131+
}
132+
82133
/**
83134
* {@inheritdoc}
84135
*/

0 commit comments

Comments
 (0)