Skip to content

Commit dbd074f

Browse files
authored
Merge pull request php-amqplib#630 from Shivox/process-signal-handling
Fix and add test for signal handling with PCNTL extension
2 parents 4664f9f + 11fdee9 commit dbd074f

File tree

2 files changed

+54
-9
lines changed

2 files changed

+54
-9
lines changed

PhpAmqpLib/Wire/IO/StreamIO.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ class StreamIO extends AbstractIO
5555
private $canDispatchPcntlSignal;
5656

5757
/** @var string */
58-
private static $ERRNO_EQUALS_EAGAIN;
58+
private static $SOCKET_STRERROR_EAGAIN;
5959

6060
/** @var string */
61-
private static $ERRNO_EQUALS_EWOULDBLOCK;
61+
private static $SOCKET_STRERROR_EWOULDBLOCK;
6262

6363
/** @var string */
64-
private static $ERRNO_EQUALS_EINTR;
64+
private static $SOCKET_STRERROR_EINTR;
6565

6666
/**
6767
* @param string $host
@@ -85,10 +85,10 @@ public function __construct(
8585
throw new \InvalidArgumentException('read_write_timeout must be at least 2x the heartbeat');
8686
}
8787

88-
// SOCKET_EAGAIN can't be accessed in Windows
89-
self::$ERRNO_EQUALS_EAGAIN = 'errno=' . (defined('SOCKET_EAGAIN') ? SOCKET_EAGAIN : SOCKET_EWOULDBLOCK);
90-
self::$ERRNO_EQUALS_EWOULDBLOCK = 'errno=' . SOCKET_EWOULDBLOCK;
91-
self::$ERRNO_EQUALS_EINTR = 'errno=' . SOCKET_EINTR;
88+
// SOCKET_EAGAIN is not defined in Windows
89+
self::$SOCKET_STRERROR_EAGAIN = socket_strerror(defined(SOCKET_EAGAIN) ? SOCKET_EAGAIN : SOCKET_EWOULDBLOCK);
90+
self::$SOCKET_STRERROR_EWOULDBLOCK = socket_strerror(SOCKET_EWOULDBLOCK);
91+
self::$SOCKET_STRERROR_EINTR = socket_strerror(SOCKET_EINTR);
9292

9393
$this->protocol = 'tcp';
9494
$this->host = $host;
@@ -347,13 +347,14 @@ public function write($data)
347347
public function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
348348
{
349349
// fwrite notice that the stream isn't ready - EAGAIN or EWOULDBLOCK
350-
if (strpos($errstr, self::$ERRNO_EQUALS_EAGAIN) !== false || strpos($errstr, self::$ERRNO_EQUALS_EWOULDBLOCK) !== false) {
350+
if (strpos($errstr, self::$SOCKET_STRERROR_EAGAIN) !== false
351+
|| strpos($errstr, self::$SOCKET_STRERROR_EWOULDBLOCK) !== false) {
351352
// it's allowed to retry
352353
return null;
353354
}
354355

355356
// stream_select warning that it has been interrupted by a signal - EINTR
356-
if (strpos($errstr, self::$ERRNO_EQUALS_EINTR) !== false) {
357+
if (strpos($errstr, self::$SOCKET_STRERROR_EINTR) !== false) {
357358
// it's allowed while processing signals
358359
return null;
359360
}

tests/Functional/Bug/Bug458Test.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace PhpAmqpLib\Tests\Functional\Bug;
4+
5+
use PhpAmqpLib\Connection\AMQPStreamConnection;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class Bug458Test extends TestCase
9+
{
10+
private $channel;
11+
12+
public function setUp()
13+
{
14+
if (!extension_loaded('pcntl')) {
15+
$this->markTestSkipped('pcntl extension is not available');
16+
}
17+
18+
$connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
19+
20+
$this->channel = $connection->channel();
21+
$this->addSignalHandlers();
22+
}
23+
24+
/**
25+
* This test will be skipped in Windows, because pcntl extension is not available there
26+
*
27+
* @test
28+
*
29+
* @expectedException PhpAmqpLib\Exception\AMQPIOWaitException
30+
*/
31+
public function stream_select_interruption()
32+
{
33+
$pid = getmypid();
34+
exec('php -r "sleep(1);posix_kill(' . $pid . ', SIGTERM);" > /dev/null 2>/dev/null &');
35+
$this->channel->wait(null, false, 2);
36+
}
37+
38+
private function addSignalHandlers()
39+
{
40+
pcntl_signal(SIGTERM, function () {
41+
// do nothing
42+
});
43+
}
44+
}

0 commit comments

Comments
 (0)