Skip to content

Commit 65c0a9b

Browse files
committed
Reworked signal handling to keep the loop running as long as there are any signal handlers registered to the loop
1 parent cba4891 commit 65c0a9b

File tree

8 files changed

+52
-10
lines changed

8 files changed

+52
-10
lines changed

examples/04-signals.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,4 @@
1010
$loop->stop();
1111
});
1212

13-
// This timer is here to keep the loop alive, signaling by itself doesn't do that
14-
$loop->addPeriodicTimer(1, function () {
15-
echo 'Timer tick', PHP_EOL;
16-
});
17-
1813
$loop->run();

src/ExtEventLoop.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function __construct(EventBaseConfig $config = null)
3535
$this->timerEvents = new SplObjectStorage();
3636

3737
$this->signals = new SignalsHandler(
38+
$this,
3839
function ($signal) {
3940
$this->signalEvents[$signal] = Event::signal($this->eventBase, $signal, $f = function () use ($signal, &$f) {
4041
$this->signals->call($signal);

src/LibEvLoop.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function __construct()
3333
$this->timerEvents = new SplObjectStorage();
3434

3535
$this->signals = new SignalsHandler(
36+
$this,
3637
function ($signal) {
3738
$this->signalEvents[$signal] = new SignalEvent($f = function () use ($signal, &$f) {
3839
$this->signals->call($signal);

src/LibEventLoop.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public function __construct()
3737
$this->timerEvents = new SplObjectStorage();
3838

3939
$this->signals = new SignalsHandler(
40+
$this,
4041
function ($signal) {
4142
$this->signalEvents[$signal] = event_new();
4243
event_set($this->signalEvents[$signal], $signal, EV_PERSIST | EV_SIGNAL, $f = function () use ($signal, &$f) {

src/SignalsHandler.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@
22

33
namespace React\EventLoop;
44

5+
use React\EventLoop\Timer\TimerInterface;
6+
57
/**
68
* @internal
79
*/
810
final class SignalsHandler
911
{
12+
private $loop;
13+
private $timer;
1014
private $signals = [];
1115
private $on;
1216
private $off;
1317

14-
public function __construct(callable $on, callable $off)
18+
public function __construct(LoopInterface $loop, callable $on, callable $off)
1519
{
20+
$this->loop = $loop;
1621
$this->on = $on;
1722
$this->off = $off;
1823
}
@@ -27,6 +32,10 @@ public function __destruct()
2732

2833
public function add($signal, callable $listener)
2934
{
35+
if (count($this->signals) == 0 && $this->timer === null) {
36+
$this->timer = $this->loop->addPeriodicTimer(1, function () {});
37+
}
38+
3039
if (!isset($this->signals[$signal])) {
3140
$this->signals[$signal] = [];
3241

@@ -56,6 +65,11 @@ public function remove($signal, callable $listener)
5665
$off = $this->off;
5766
$off($signal);
5867
}
68+
69+
if (count($this->signals) == 0 && $this->timer instanceof TimerInterface) {
70+
$this->loop->cancelTimer($this->timer);
71+
$this->timer = null;
72+
}
5973
}
6074

6175
public function call($signal)

src/StreamSelectLoop.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function __construct()
3131
$this->timers = new Timers();
3232
$this->pcntl = extension_loaded('pcntl');
3333
$this->signals = new SignalsHandler(
34+
$this,
3435
function ($signal) {
3536
\pcntl_signal($signal, $f = function ($signal) use (&$f) {
3637
$this->signals->call($signal);

tests/AbstractLoopTest.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,39 @@ public function testSignalMultipleUsagesForTheSameListener()
453453
$this->assertSame(1, $funcCallCount);
454454
}
455455

456-
public function testSignalsDontKeepTheLoopRunning()
456+
public function testSignalsKeepTheLoopRunning()
457457
{
458-
$this->loop->addSignal(SIGUSR1, function () {});
459-
$this->loop->addTimer(0.1, function () {});
458+
$function = function () {};
459+
$this->loop->addSignal(SIGUSR1, $function);
460+
$this->loop->addTimer(1.5, function () use ($function) {
461+
$this->loop->removeSignal(SIGUSR1, $function);
462+
$this->loop->stop();
463+
});
464+
465+
$this->assertRunSlowerThan(1.5);
466+
}
467+
468+
public function testSignalsKeepTheLoopRunningAndRemovingItStopsTheLoop()
469+
{
470+
$function = function () {};
471+
$this->loop->addSignal(SIGUSR1, $function);
472+
$this->loop->addTimer(1.5, function () use ($function) {
473+
$this->loop->removeSignal(SIGUSR1, $function);
474+
});
475+
476+
$this->assertRunFasterThan(1.6);
477+
}
478+
479+
private function assertRunSlowerThan($minInterval)
480+
{
481+
$start = microtime(true);
482+
483+
$this->loop->run();
484+
485+
$end = microtime(true);
486+
$interval = $end - $start;
460487

461-
$this->assertRunFasterThan(0.2);
488+
$this->assertLessThan($interval, $minInterval);
462489
}
463490

464491
private function assertRunFasterThan($maxInterval)

tests/SignalsHandlerTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace React\Tests\EventLoop;
44

5+
use React\EventLoop\Factory;
56
use React\EventLoop\SignalsHandler;
67

78
final class SignalsHandlerTest extends TestCase
@@ -15,6 +16,7 @@ public function testEmittedEventsAndCallHandling()
1516
$callCount++;
1617
};
1718
$signals = new SignalsHandler(
19+
Factory::create(),
1820
function () use (&$onCount) {
1921
$onCount++;
2022
},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy