Skip to content

Commit 5da8da1

Browse files
authored
Merge pull request #132 from clue-labs/overflow-32bit
Ensure large timer interval does not overflow on 32bit systems
2 parents 7d13733 + 06cc5bf commit 5da8da1

File tree

3 files changed

+24
-38
lines changed

3 files changed

+24
-38
lines changed

src/StreamSelectLoop.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ public function run()
195195
if ($timeout < 0) {
196196
$timeout = 0;
197197
} else {
198-
/*
199-
* round() needed to correct float error:
200-
* https://github.com/reactphp/event-loop/issues/48
201-
*/
202-
$timeout = round($timeout * self::MICROSECONDS_PER_SECOND);
198+
// Convert float seconds to int microseconds.
199+
// Ensure we do not exceed maximum integer size, which may
200+
// cause the loop to tick once every ~35min on 32bit systems.
201+
$timeout *= self::MICROSECONDS_PER_SECOND;
202+
$timeout = $timeout > PHP_INT_MAX ? PHP_INT_MAX : (int)$timeout;
203203
}
204204

205205
// The only possible event is stream activity, so wait forever ...
@@ -222,6 +222,8 @@ public function stop()
222222

223223
/**
224224
* Wait/check for stream activity, or until the next timer is due.
225+
*
226+
* @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
225227
*/
226228
private function waitForStreamActivity($timeout)
227229
{

tests/AbstractLoopTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,23 @@ public function testSignalsKeepTheLoopRunningAndRemovingItStopsTheLoop()
480480
$this->assertRunFasterThan(1.6);
481481
}
482482

483+
public function testTimerIntervalCanBeFarInFuture()
484+
{
485+
// get only one part of the pair to ensure the other side will close immediately
486+
list($stream) = $this->createSocketPair();
487+
488+
// start a timer very far in the future
489+
$timer = $this->loop->addTimer(PHP_INT_MAX, function () { });
490+
491+
// remove stream and timer when the stream is readable (closes)
492+
$this->loop->addReadStream($stream, function ($stream) use ($timer) {
493+
$this->loop->removeReadStream($stream);
494+
$this->loop->cancelTimer($timer);
495+
});
496+
497+
$this->assertRunFasterThan($this->tickTimeout);
498+
}
499+
483500
private function assertRunSlowerThan($minInterval)
484501
{
485502
$start = microtime(true);

tests/StreamSelectLoopTest.php

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use React\EventLoop\LoopInterface;
66
use React\EventLoop\StreamSelectLoop;
7-
use React\EventLoop\Timer\Timer;
87

98
class StreamSelectLoopTest extends AbstractLoopTest
109
{
@@ -144,36 +143,4 @@ protected function forkSendSignal($signal)
144143
die();
145144
}
146145
}
147-
148-
/**
149-
* https://github.com/reactphp/event-loop/issues/48
150-
*
151-
* Tests that timer with very small interval uses at least 1 microsecond
152-
* timeout.
153-
*/
154-
public function testSmallTimerInterval()
155-
{
156-
/** @var StreamSelectLoop|\PHPUnit_Framework_MockObject_MockObject $loop */
157-
$loop = $this->getMockBuilder('React\EventLoop\StreamSelectLoop')
158-
->setMethods(['streamSelect'])
159-
->getMock();
160-
$loop
161-
->expects($this->at(0))
162-
->method('streamSelect')
163-
->with([], [], 1);
164-
$loop
165-
->expects($this->at(1))
166-
->method('streamSelect')
167-
->with([], [], 0);
168-
169-
$callsCount = 0;
170-
$loop->addPeriodicTimer(Timer::MIN_INTERVAL, function() use (&$loop, &$callsCount) {
171-
$callsCount++;
172-
if ($callsCount == 2) {
173-
$loop->stop();
174-
}
175-
});
176-
177-
$loop->run();
178-
}
179146
}

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