mirror of
https://github.com/danog/amp.git
synced 2024-11-30 04:29:08 +01:00
Add Loop::now()
This commit is contained in:
parent
96c2eeaa1f
commit
77a12c823b
12
lib/Loop.php
12
lib/Loop.php
@ -332,6 +332,18 @@ final class Loop
|
||||
self::$driver->unreference($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to
|
||||
* wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned
|
||||
* by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function now(): int
|
||||
{
|
||||
return self::$driver->now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores information in the loop bound registry.
|
||||
*
|
||||
|
@ -590,6 +590,20 @@ abstract class Driver
|
||||
($this->errorHandler)($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to
|
||||
* wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned
|
||||
* by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick.
|
||||
*
|
||||
* Extending classes should override this function to return a value cached once per loop tick.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
return \microtime(true) * self::MILLISEC_PER_SEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying loop handle.
|
||||
*
|
||||
|
@ -11,22 +11,38 @@ class EvDriver extends Driver
|
||||
{
|
||||
/** @var \EvSignal[]|null */
|
||||
private static $activeSignals;
|
||||
|
||||
/** @var \EvLoop */
|
||||
private $handle;
|
||||
|
||||
/** @var \EvWatcher[] */
|
||||
private $events = [];
|
||||
|
||||
/** @var callable */
|
||||
private $ioCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $timerCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $signalCallback;
|
||||
|
||||
/** @var \EvSignal[] */
|
||||
private $signals = [];
|
||||
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now = 0;
|
||||
|
||||
/** @var bool */
|
||||
private $nowUpdateNeeded = false;
|
||||
|
||||
/** @var int Loop time offset from microtime() */
|
||||
private $nowOffset;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->handle = new \EvLoop;
|
||||
$this->nowOffset = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
|
||||
if (self::$activeSignals === null) {
|
||||
self::$activeSignals = &$this->signals;
|
||||
@ -179,6 +195,19 @@ class EvDriver extends Driver
|
||||
parent::stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
if ($this->nowUpdateNeeded) {
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC) - $this->nowOffset;
|
||||
$this->nowUpdateNeeded = false;
|
||||
}
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -192,6 +221,7 @@ class EvDriver extends Driver
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->nowUpdateNeeded = true;
|
||||
$this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT);
|
||||
}
|
||||
|
||||
|
@ -11,25 +11,38 @@ class EventDriver extends Driver
|
||||
{
|
||||
/** @var \Event[]|null */
|
||||
private static $activeSignals;
|
||||
|
||||
/** @var \EventBase */
|
||||
private $handle;
|
||||
|
||||
/** @var \Event[] */
|
||||
private $events = [];
|
||||
|
||||
/** @var callable */
|
||||
private $ioCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $timerCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $signalCallback;
|
||||
|
||||
/** @var \Event[] */
|
||||
private $signals = [];
|
||||
|
||||
/** @var bool */
|
||||
private $nowUpdateNeeded = false;
|
||||
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now;
|
||||
private $now = 0;
|
||||
|
||||
/** @var int Loop time offset from microtime() */
|
||||
private $nowOffset;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->handle = new \EventBase;
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
$this->nowOffset = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
|
||||
if (self::$activeSignals === null) {
|
||||
self::$activeSignals = &$this->signals;
|
||||
@ -184,6 +197,19 @@ class EventDriver extends Driver
|
||||
parent::stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
if ($this->nowUpdateNeeded) {
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC) - $this->nowOffset;
|
||||
$this->nowUpdateNeeded = false;
|
||||
}
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -197,8 +223,8 @@ class EventDriver extends Driver
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->nowUpdateNeeded = true;
|
||||
$this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK);
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,7 +232,7 @@ class EventDriver extends Driver
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
$now = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
$now = (int) (\microtime(true) * self::MILLISEC_PER_SEC) - $this->nowOffset;
|
||||
|
||||
foreach ($watchers as $watcher) {
|
||||
if (!isset($this->events[$id = $watcher->id])) {
|
||||
@ -262,7 +288,7 @@ class EventDriver extends Driver
|
||||
switch ($watcher->type) {
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
$interval = $watcher->value - ($now - $this->now);
|
||||
$interval = $watcher->value - ($now - $this->now());
|
||||
$this->events[$id]->add($interval > 0 ? $interval / self::MILLISEC_PER_SEC : 0);
|
||||
break;
|
||||
|
||||
|
@ -30,8 +30,14 @@ class NativeDriver extends Driver
|
||||
/** @var \Amp\Loop\Watcher[][] */
|
||||
private $signalWatchers = [];
|
||||
|
||||
/** @var bool */
|
||||
private $nowUpdateNeeded = false;
|
||||
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now;
|
||||
private $now = 0;
|
||||
|
||||
/** @var int Loop time offset from microtime() */
|
||||
private $nowOffset;
|
||||
|
||||
/** @var bool */
|
||||
private $signalHandling;
|
||||
@ -40,7 +46,7 @@ class NativeDriver extends Driver
|
||||
{
|
||||
$this->timerQueue = new \SplPriorityQueue();
|
||||
$this->signalHandling = \extension_loaded("pcntl");
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
$this->nowOffset = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,6 +63,19 @@ class NativeDriver extends Driver
|
||||
return parent::onSignal($signo, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
if ($this->nowUpdateNeeded) {
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC) - $this->nowOffset;
|
||||
$this->nowUpdateNeeded = false;
|
||||
}
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -67,14 +86,14 @@ class NativeDriver extends Driver
|
||||
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->nowUpdateNeeded = true;
|
||||
|
||||
$this->selectStreams(
|
||||
$this->readStreams,
|
||||
$this->writeStreams,
|
||||
$blocking ? $this->getTimeout() : 0
|
||||
);
|
||||
|
||||
$this->now = (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
|
||||
if (!empty($this->timerExpires)) {
|
||||
$scheduleQueue = [];
|
||||
|
||||
@ -89,14 +108,14 @@ class NativeDriver extends Driver
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->timerExpires[$id] > $this->now) { // Timer at top of queue has not expired.
|
||||
if ($this->timerExpires[$id] > $this->now()) { // Timer at top of queue has not expired.
|
||||
break;
|
||||
}
|
||||
|
||||
$this->timerQueue->extract();
|
||||
|
||||
if ($watcher->type & Watcher::REPEAT) {
|
||||
$expiration = $this->now + $watcher->value;
|
||||
$expiration = $this->now() + $watcher->value;
|
||||
$this->timerExpires[$watcher->id] = $expiration;
|
||||
$scheduleQueue[] = [$watcher, $expiration];
|
||||
} else {
|
||||
@ -283,7 +302,7 @@ class NativeDriver extends Driver
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
$expiration = $this->now + $watcher->value;
|
||||
$expiration = $this->now() + $watcher->value;
|
||||
$this->timerExpires[$watcher->id] = $expiration;
|
||||
$this->timerQueue->insert([$watcher, $expiration], -$expiration);
|
||||
break;
|
||||
|
@ -166,6 +166,14 @@ class UvDriver extends Driver
|
||||
return \extension_loaded("uv");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
return \uv_now($this->handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -1555,6 +1555,23 @@ abstract class DriverTest extends TestCase
|
||||
$this->assertNotSame(0, $j);
|
||||
}
|
||||
|
||||
public function testNow()
|
||||
{
|
||||
$now = $this->loop->now();
|
||||
$this->loop->delay(100, function () use ($now) {
|
||||
$now += 100;
|
||||
$new = $this->loop->now();
|
||||
|
||||
// Allow a few milliseconds of inaccuracy.
|
||||
$this->assertGreaterThanOrEqual($now - 5, $new);
|
||||
$this->assertLessThanOrEqual($now + 5, $new);
|
||||
|
||||
// Same time should be returned from later call.
|
||||
$this->assertSame($new, $this->loop->now());
|
||||
});
|
||||
$this->loop->run();
|
||||
}
|
||||
|
||||
public function testBug163ConsecutiveDelayed()
|
||||
{
|
||||
$emits = 3;
|
||||
|
@ -46,12 +46,30 @@ class LoopTest extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
public function testNow()
|
||||
{
|
||||
Loop::run(function () {
|
||||
$now = Loop::now();
|
||||
Loop::delay(100, function () use ($now) {
|
||||
$now += 100;
|
||||
$new = Loop::now();
|
||||
|
||||
// Allow a few milliseconds of inaccuracy.
|
||||
$this->assertGreaterThanOrEqual($now - 5, $new);
|
||||
$this->assertLessThanOrEqual($now + 5, $new);
|
||||
|
||||
// Same time should be returned from later call.
|
||||
$this->assertSame($new, Loop::now());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$this->assertInstanceOf(Loop\Driver::class, Loop::get());
|
||||
}
|
||||
|
||||
public function testGetInto()
|
||||
public function testGetInfo()
|
||||
{
|
||||
$this->assertSame(Loop::get()->getInfo(), Loop::getInfo());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user