8000 [EventLoop] Reimplement timers for StreamSelectLoop. · Undefined-Variables/event-loop@e37b2a5 · GitHub
[go: up one dir, main page]

Skip to content

Commit e37b2a5

Browse files
committed
[EventLoop] Reimplement timers for StreamSelectLoop.
1 parent 431f6f5 commit e37b2a5

File tree

3 files changed

+56
-45
lines changed

3 files changed

+56
-45
lines changed

LoopInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function removeStream($stream);
1313

1414
public function addTimer($interval, $callback);
1515
public function addPeriodicTimer($interval, $callback);
16-
public function cancelTimer($signature);
16+
public function cancelTimer($timer);
1717

1818
public function tick();
1919
public function run();

StreamSelectLoop.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace React\EventLoop;
44

5+
use React\EventLoop\Timer\Timer;
6+
use React\EventLoop\Timer\TimerInterface;
57
use React\EventLoop\Timer\Timers;
68

79
class StreamSelectLoop implements LoopInterface
@@ -17,7 +19,7 @@ class StreamSelectLoop implements LoopInterface
1719

1820
public function __construct()
1921
{
20-
$this->timers = new Timers($this);
22+
$this->timers = new Timers();
2123
}
2224

2325
public function addReadStream($stream, $listener)
@@ -68,17 +70,23 @@ public function removeStream($stream)
6870

6971
public function addTimer($interval, $callback)
7072
{
71-
return $this->timers->add($interval, $callback);
73+
$timer = new Timer($this, $interval, $callback, false);
74+
$this->timers->add($timer);
75+
76+
return $timer;
7277
}
7378

7479
public function addPeriodicTimer($interval, $callback)
7580
{
76-
return $this->timers->add($interval, $callback, true);
81+
$timer = new Timer($this, $interval, $callback, true);
82+
$this->timers->add($timer);
83+
84+
return $timer;
7785
}
7886

79-
public function cancelTimer($signature)
87+
public function cancelTimer($timer)
8088
{
81-
$this->timers->cancel($signature);
89+
$this->timers->cancel($timer);
8290
}
8391

8492
protected function getNextEventTimeInMicroSeconds()

Timer/Timers.php

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@
22

33
namespace React\EventLoop\Timer;
44

5+
use SplObjectStorage;
6+
use SplPriorityQueue;
7+
use InvalidArgumentException;
58
use React\EventLoop\LoopInterface;
69

710
class Timers
811
{
912
const MIN_RESOLUTION = 0.001;
1013

11-
private $loop;
1214
private $time;
13-
private $active = array();
1415
private $timers;
16+
private $scheduler;
1517

16-
public function __construct(LoopInterface $loop)
18+
public function __construct()
1719
{
18-
$this->loop = $loop;
19-
$this->timers = new \SplPriorityQueue();
20+
$this->timers = new SplObjectStorage();
21+
$this->scheduler = new SplPriorityQueue();
2022
}
2123

2224
public function updateTime()
@@ -29,68 +31,69 @@ public function getTime()
2931
return $this->time ?: $this->updateTime();
3032
}
3133

32-
public function add($interval, $callback, $periodic = false)
34+
public function add(TimerInterface $timer)
3335
{
34-
if ($interval < self::MIN_RESOLUTION) {
35-
throw new \InvalidArgumentException('Timer events do not support sub-millisecond timeouts.');
36-
}
36+
$interval = $timer->getInterval();
3737

38-
if (!is_callable($callback)) {
39-
throw new \InvalidArgumentException('The callback must be a callable object.');
38+
if ($interval < self::MIN_RESOLUTION) {
39+
throw new InvalidArgumentException('Timer events do not support sub-millisecond timeouts.');
4040
}
4141

42-
$interval = (float) $interval;
42+
$scheduledAt = $interval + $this->getTime();
4343

44-
$timer = (object) array(
45-
'interval' => $interval,
46-
'callback' => $callback,
47-
'periodic' => $periodic,
48-
'scheduled' => $interval + $this->getTime(),
49-
);
50-
51-
$timer->signature = spl_object_hash($timer);
52-
$this->timers->insert($timer, -$timer->scheduled);
53-
$this->active[$timer->signature] = $timer;
54-
55-
return $timer->signature;
44+
$this->timers->attach($timer, $scheduledAt);
45+
$this->scheduler->insert($timer, -$scheduledAt);
5646
}
5747

58-
public function cancel($signature)
48+
public function cancel(TimerInterface $timer)
5949
{
60-
unset($this->active[$signature]);
50+
$this->timers->detach($timer);
6151
}
6252

6353
public function getFirst()
6454
{
65-
if ($this->timers->isEmpty()) {
55+
if ($this->scheduler->isEmpty()) {
6656
return null;
6757
}
6858

69-
return $this->timers->top()->scheduled;
59+
$scheduledAt = $this->timers[$this->scheduler->top()];
60+
61+
return $scheduledAt;
7062
}
7163

7264
public function isEmpty()
7365
{
74-
return !$this->active;
66+
return count($this->timers) === 0;
7567
}
7668

7769
public function tick()
7870
{
7971
$time = $this->updateTime();
8072
$timers = $this->timers;
73+
$scheduler = $this->scheduler;
8174

82-
while (!$timers->isEmpty() && $timers->top()->scheduled < $time) {
83-
$timer = $timers->extract();
75+
while ($scheduler->isEmpty() === false) {
76+
$timer = $scheduler->top();
77+
78+
if (isset($timers[$timer]) === false) {
79+
$scheduler->extract();
80+
$timers->detach($timer);
81+
82+
continue;
83+
}
84+
85+
if ($timers[$timer] >= $time) {
86+
break;
87+
}
8488

85-
if (isset($this->active[$timer->signature])) {
86-
call_user_func($timer->callback, $timer->signature, $this->loop);
89+
$scheduler->extract();
90+
call_user_func($timer->getCallback(), $timer);
8791

88-
if ($timer->periodic === true) {
89-
$timer->scheduled = $timer->interval + $time;
90-
$timers->insert($timer, -$timer->scheduled);
91-
} else {
92-
unset($this->active[$timer->signature]);
93-
}
92+
if ($timer->isPeriodic() && isset($timers[$timer])) {
93+
$timers[$timer] = $scheduledAt = $timer->getInterval() + $time;
94+
$scheduler->insert($timer, -$scheduledAt);
95+
} else {
96+
$timers->detach($timer);
9497
}
9598
}
9699
}

0 commit comments

Comments
 (0)
0