Skip to content

Commit a4aa2c4

Browse files
committed
Implemented LoopInterface::futureTick().
1 parent 480b437 commit a4aa2c4

File tree

5 files changed

+125
-6
lines changed

5 files changed

+125
-6
lines changed

LibEvLoop.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use libev\EventLoop;
66
use libev\IOEvent;
77
use libev\TimerEvent;
8+
use React\EventLoop\Tick\FutureTickQueue;
89
use React\EventLoop\Tick\NextTickQueue;
910
use React\EventLoop\Timer\Timer;
1011
use React\EventLoop\Timer\TimerInterface;
@@ -18,6 +19,7 @@ class LibEvLoop implements LoopInterface
1819
{
1920
private $loop;
2021
private $nextTickQueue;
22+
private $futureTickQueue;
2123
private $timerEvents;
2224
private $readEvents = [];
2325
private $writeEvents = [];
@@ -27,6 +29,7 @@ public function __construct()
2729
{
2830
$this->loop = new EventLoop();
2931
$this->nextTickQueue = new NextTickQueue($this);
32+
$this->futureTickQueue = new FutureTickQueue($this);
3033
$this->timerEvents = new SplObjectStorage();
3134
}
3235

@@ -162,13 +165,23 @@ public function nextTick(callable $listener)
162165
$this->nextTickQueue->add($listener);
163166
}
164167

168+
/**
169+
* {@inheritdoc}
170+
*/
171+
public function futureTick(callable $listener)
172+
{
173+
$this->futureTickQueue->add($listener);
174+
}
175+
165176
/**
166177
* {@inheritdoc}
167178
*/
168179
public function tick()
169180
{
170181
$this->nextTickQueue->tick();
171182

183+
$this->futureTickQueue->tick();
184+
172185
$this->loop->run(EventLoop::RUN_ONCE | EventLoop::RUN_NOWAIT);
173186
}
174187

@@ -182,11 +195,16 @@ public function run()
182195
while ($this->running) {
183196
$this->nextTickQueue->tick();
184197

185-
if (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count()) {
198+
$this->futureTickQueue->tick();
199+
200+
$flags = EventLoop::RUN_ONCE;
201+
if (!$this->futureTickQueue->isEmpty()) {
202+
$flags |= EventLoop::RUN_NOWAIT;
203+
} elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count()) {
186204
break;
187205
}
188206

189-
$this->loop->run(EventLoop::RUN_ONCE);
207+
$this->loop->run($flags);
190208
}
191209
}
192210

LibEventLoop.php

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

55
use Event;
66
use EventBase;
7+
use React\EventLoop\Tick\FutureTickQueue;
78
use React\EventLoop\Tick\NextTickQueue;
89
use React\EventLoop\Timer\Timer;
910
use React\EventLoop\Timer\TimerInterface;
@@ -18,6 +19,7 @@ class LibEventLoop implements LoopInterface
1819

1920
private $eventBase;
2021
private $nextTickQueue;
22+
private $futureTickQueue;
2123
private $timerCallback;
2224
private $timerEvents;
2325
private $streamCallback;
@@ -31,6 +33,7 @@ public function __construct()
3133
{
3234
$this->eventBase = event_base_new();
3335
$this->nextTickQueue = new NextTickQueue($this);
36+
$this->futureTickQueue = new FutureTickQueue($this);
3437
$this->timerEvents = new SplObjectStorage();
3538

3639
$this->createTimerCallback();
@@ -166,13 +169,23 @@ public function nextTick(callable $listener)
166169
$this->nextTickQueue->add($listener);
167170
}
168171

172+
/**
173+
* {@inheritdoc}
174+
*/
175+
public function futureTick(callable $listener)
176+
{
177+
$this->futureTickQueue->add($listener);
178+
}
179+
169180
/**
170181
* {@inheritdoc}
171182
*/
172183
public function tick()
173184
{
174185
$this->nextTickQueue->tick();
175186

187+
$this->futureTickQueue->tick();
188+
176189
event_base_loop($this->eventBase, EVLOOP_ONCE | EVLOOP_NONBLOCK);
177190
}
178191

@@ -186,11 +199,16 @@ public function run()
186199
while ($this->running) {
187200
$this->nextTickQueue->tick();
188201

189-
if (!$this->streamEvents && !$this->timerEvents->count()) {
202+
$this->futureTickQueue->tick();
203+
204+
$flags = EVLOOP_ONCE;
205+
if (!$this->futureTickQueue->isEmpty()) {
206+
$flags |= EVLOOP_NONBLOCK;
207+
} elseif (!$this->streamEvents && !$this->timerEvents->count()) {
190208
break;
191209
}
192210

193-
event_base_loop($this->eventBase, EVLOOP_ONCE);
211+
event_base_loop($this->eventBase, $flags);
194212
}
195213
}
196214

LoopInterface.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ public function isTimerActive(TimerInterface $timer);
9595
*/
9696
public function nextTick(callable $listener);
9797

98+
/**
99+
* Schedule a callback to be invoked on a future tick of the event loop.
100+
*
101+
* Callbacks are guaranteed to be executed in the order they are enqueued.
102+
*
103+
* @param callable $listener The callback to invoke.
104+
*/
105+
public function futureTick(callable $listener);
106+
98107
/**
99108
* Perform a single iteration of the event loop.
100109
*/

StreamSelectLoop.php

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

33
namespace React\EventLoop;
44

5+
use React\EventLoop\Tick\FutureTickQueue;
56
use React\EventLoop\Tick\NextTickQueue;
67
use React\EventLoop\Timer\Timer;
78
use React\EventLoop\Timer\TimerInterface;
@@ -13,6 +14,7 @@
1314
class StreamSelectLoop implements LoopInterface
1415
{
1516
private $nextTickQueue;
17+
private $futureTickQueue;
1618
private $timers;
1719
private $readStreams = [];
1820
private $readListeners = [];
@@ -23,6 +25,7 @@ class StreamSelectLoop implements LoopInterface
2325
public function __construct()
2426
{
2527
$this->nextTickQueue = new NextTickQueue($this);
28+
$this->futureTickQueue = new FutureTickQueue($this);
2629
$this->timers = new Timers();
2730
}
2831

@@ -135,13 +138,23 @@ public function nextTick(callable $listener)
135138
$this->nextTickQueue->add($listener);
136139
}
137140

141+
/**
142+
* {@inheritdoc}
143+
*/
144+
public function futureTick(callable $listener)
145+
{
146+
$this->futureTickQueue->add($listener);
147+
}
148+
138149
/**
139150
* {@inheritdoc}
140151
*/
141152
public function tick()
142153
{
143154
$this->nextTickQueue->tick();
144155

156+
$this->futureTickQueue->tick();
157+
145158
$this->timers->tick();
146159

147160
$this->waitForStreamActivity(0);
@@ -157,10 +170,12 @@ public function run()
157170
while ($this->running) {
158171
$this->nextTickQueue->tick();
159172

173+
$this->futureTickQueue->tick();
174+
160175
$this->timers->tick();
161176

162-
// Timers have placed more items on the next-tick queue ...
163-
if (!$this->nextTickQueue->isEmpty()) {
177+
// Next-tick or future-tick queues have pending callbacks ...
178+
if (!$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) {
164179
$timeout = 0;
165180

166181
// There is a pending timer, only block until it is due ...

Tick/FutureTickQueue.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace React\EventLoop\Tick;
4+
5+
use React\EventLoop\LoopInterface;
6+
use SplQueue;
7+
8+
class FutureTickQueue
9+
{
10+
private $eventLoop;
11+
private $queue;
12+
13+
/**
14+
* @param LoopInterface $eventLoop The event loop passed as the first parameter to callbacks.
15+
*/
16+
public function __construct(LoopInterface $eventLoop)
17+
{
18+
$this->eventLoop = $eventLoop;
19+
$this->queue = new SplQueue();
20+
}
21+
22+
/**
23+
* Add a callback to be invoked on a future tick of the event loop.
24+
*
25+
* Callbacks are guaranteed to be executed in the order they are enqueued.
26+
*
27+
* @param callable $listener The callback to invoke.
28+
*/
29+
public function add(callable $listener)
30+
{
31+
$this->queue->enqueue($listener);
32+
}
33+
34+
/**
35+
* Flush the callback queue.
36+
*/
37+
public function tick()
38+
{
39+
// Only invoke as many callbacks as were on the queue when tick() was called.
40+
$count = $this->queue->count();
41+
42+
while ($count--) {
43+
call_user_func(
44+
$this->queue->dequeue(),
45+
$this->eventLoop
46+
);
47+
}
48+
}
49+
50+
/**
51+
* Check if the next tick queue is empty.
52+
*
53+
* @return boolean
54+
*/
55+
public function isEmpty()
56+
{
57+
return $this->queue->isEmpty();
58+
}
59+
}

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