1
0
mirror of https://github.com/danog/amp.git synced 2024-11-26 20:15:00 +01:00

Fix timers with interval = 0 in NativeDriver

This commit is contained in:
Niklas Keller 2017-05-22 19:54:04 +02:00
parent 5bca41ade4
commit dbc853c3f1
2 changed files with 58 additions and 31 deletions

View File

@ -69,43 +69,51 @@ class NativeDriver extends Driver {
);
if (!empty($this->timerExpires)) {
while (!$this->timerQueue->isEmpty()) {
list($watcher, $expiration) = $this->timerQueue->top();
$scheduleQueue = [];
$id = $watcher->id;
try {
while (!$this->timerQueue->isEmpty()) {
list($watcher, $expiration) = $this->timerQueue->top();
if (!isset($this->timerExpires[$id]) || $expiration !== $this->timerExpires[$id]) {
$this->timerQueue->extract(); // Timer was removed from queue.
continue;
}
$id = $watcher->id;
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;
$this->timerExpires[$watcher->id] = $expiration;
$this->timerQueue->insert([$watcher, $expiration], -$expiration);
} else {
$this->cancel($id);
}
try {
// Execute the timer.
$result = ($watcher->callback)($id, $watcher->data);
if ($result instanceof \Generator) {
$result = new Coroutine($result);
if (!isset($this->timerExpires[$id]) || $expiration !== $this->timerExpires[$id]) {
$this->timerQueue->extract(); // Timer was removed from queue.
continue;
}
if ($result instanceof Promise || $result instanceof ReactPromise) {
rethrow($result);
if ($this->timerExpires[$id] > $this->now) { // Timer at top of queue has not expired.
break;
}
} catch (\Throwable $exception) {
$this->error($exception);
$this->timerQueue->extract();
if ($watcher->type & Watcher::REPEAT) {
$expiration = $this->now + $watcher->value;
$this->timerExpires[$watcher->id] = $expiration;
$scheduleQueue[] = [$watcher, $expiration];
} else {
$this->cancel($id);
}
try {
// Execute the timer.
$result = ($watcher->callback)($id, $watcher->data);
if ($result instanceof \Generator) {
$result = new Coroutine($result);
}
if ($result instanceof Promise || $result instanceof ReactPromise) {
rethrow($result);
}
} catch (\Throwable $exception) {
$this->error($exception);
}
}
} finally {
foreach ($scheduleQueue as $item) {
$this->timerQueue->insert($item, -$item[1]);
}
}
}

View File

@ -1433,4 +1433,23 @@ abstract class DriverTest extends TestCase {
});
$this->loop->run();
}
public function testShortTimerDoesNotBlockOtherTimers() {
$this->loop->repeat(0, function () {
static $i = 0;
if (++$i === 5) {
$this->fail("Loop continues with repeat watcher");
}
\usleep(2000);
});
$this->loop->delay(2, function () {
$this->assertTrue(true);
$this->loop->stop();
});
$this->loop->run();
}
}