Skip to content

Commit 3e4b3d4

Browse files
committed
Merge branch 'refs/heads/future-tick'
2 parents 9c5d786 + b98a945 commit 3e4b3d4

File tree

8 files changed

+331
-9
lines changed

8 files changed

+331
-9
lines changed

examples/next-tick.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
This example shows how nextTick and futureTick events are scheduled for
5+
execution.
6+
7+
The expected output is:
8+
9+
next-tick #1
10+
next-tick #2
11+
future-tick #1
12+
timer
13+
future-tick #2
14+
15+
Note that both nextTick and futureTick events are executed before timer and I/O
16+
events on each tick.
17+
18+
nextTick events registered inside an existing nextTick handler are guaranteed
19+
to be executed before timer and I/O handlers are processed, whereas futureTick
20+
handlers are always deferred.
21+
*/
22+
23+
require __DIR__.'/../vendor/autoload.php';
24+
25+
$loop = React\EventLoop\Factory::create();
26+
27+
$loop->addTimer(
28+
0,
29+
function () {
30+
echo 'timer' . PHP_EOL;
31+
}
32+
);
33+
34+
$loop->nextTick(
35+
function ($loop) {
36+
echo 'next-tick #1' . PHP_EOL;
37+
38+
$loop->nextTick(
39+
function () {
40+
echo 'next-tick #2' . PHP_EOL;
41+
}
42+
);
43+
}
44+
);
45+
46+
$loop->futureTick(
47+
function ($loop) {
48+
echo 'future-tick #1' . PHP_EOL;
49+
50+
$loop->futureTick(
51+
function () {
52+
echo 'future-tick #2' . PHP_EOL;
53+
}
54+
);
55+
}
56+
);
57+
58+
$loop->run();

src/React/EventLoop/ExtEventLoop.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;
@@ -16,6 +17,7 @@ class ExtEventLoop implements LoopInterface
1617
{
1718
private $eventBase;
1819
private $nextTickQueue;
20+
private $futureTickQueue;
1921
private $timerCallback;
2022
private $timerEvents;
2123
private $streamCallback;
@@ -29,6 +31,7 @@ public function __construct()
2931
{
3032
$this->eventBase = new EventBase();
3133
$this->nextTickQueue = new NextTickQueue($this);
34+
$this->futureTickQueue = new FutureTickQueue($this);
3235
$this->timerEvents = new SplObjectStorage();
3336

3437
$this->createTimerCallback();
@@ -157,13 +160,23 @@ public function nextTick(callable $listener)
157160
$this->nextTickQueue->add($listener);
158161
}
159162

163+
/**
164+
* {@inheritdoc}
165+
*/
166+
public function futureTick(callable $listener)
167+
{
168+
$this->futureTickQueue->add($listener);
169+
}
170+
160171
/**
161172
* {@inheritdoc}
162173
*/
163174
public function tick()
164175
{
165176
$this->nextTickQueue->tick();
166177

178+
$this->futureTickQueue->tick();
179+
167180
// @-suppression: https://github.com/reactphp/react/pull/234#discussion-diff-7759616R226
168181
@$this->eventBase->loop(EventBase::LOOP_ONCE | EventBase::LOOP_NONBLOCK);
169182
}
@@ -178,12 +191,17 @@ public function run()
178191
while ($this->running) {
179192
$this->nextTickQueue->tick();
180193

181-
if (!$this->streamEvents && !$this->timerEvents->count()) {
194+
$this->futureTickQueue->tick();
195+
196+
$flags = EventBase::LOOP_ONCE;
197+
if (!$this->running || !$this->futureTickQueue->isEmpty()) {
198+
$flags |= EventBase::LOOP_NONBLOCK;
199+
} elseif (!$this->streamEvents && !$this->timerEvents->count()) {
182200
break;
183201
}
184202

185203
// @-suppression: https://github.com/reactphp/react/pull/234#discussion-diff-7759616R226
186-
@$this->eventBase->loop(EventBase::LOOP_ONCE);
204+
@$this->eventBase->loop($flags);
187205
}
188206
}
189207

src/React/EventLoop/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->running || !$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

src/React/EventLoop/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->running || !$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

src/React/EventLoop/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
*/

src/React/EventLoop/StreamSelectLoop.php

Lines changed: 20 additions & 3 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;
@@ -12,7 +13,10 @@
1213
*/
1314
class StreamSelectLoop implements LoopInterface
1415
{
16+
const MICROSECONDS_PER_SECOND = 1000000;
17+
1518
private $nextTickQueue;
19+
private $futureTickQueue;
1620
private $timers;
1721
private $readStreams = [];
1822
private $readListeners = [];
@@ -23,6 +27,7 @@ class StreamSelectLoop implements LoopInterface
2327
public function __construct()
2428
{
2529
$this->nextTickQueue = new NextTickQueue($this);
30+
$this->futureTickQueue = new FutureTickQueue($this);
2631
$this->timers = new Timers();
2732
}
2833

@@ -135,13 +140,23 @@ public function nextTick(callable $listener)
135140
$this->nextTickQueue->add($listener);
136141
}
137142

143+
/**
144+
* {@inheritdoc}
145+
*/
146+
public function futureTick(callable $listener)
147+
{
148+
$this->futureTickQueue->add($listener);
149+
}
150+
138151
/**
139152
* {@inheritdoc}
140153
*/
141154
public function tick()
142155
{
143156
$this->nextTickQueue->tick();
144157

158+
$this->futureTickQueue->tick();
159+
145160
$this->timers->tick();
146161

147162
$this->waitForStreamActivity(0);
@@ -157,10 +172,12 @@ public function run()
157172
while ($this->running) {
158173
$this->nextTickQueue->tick();
159174

175+
$this->futureTickQueue->tick();
176+
160177
$this->timers->tick();
161178

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

166183
// There is a pending timer, only block until it is due ...
@@ -178,7 +195,7 @@ public function run()
178195
break;
179196
}
180197

181-
$this->waitForStreamActivity($timeout);
198+
$this->waitForStreamActivity($timeout * self::MICROSECONDS_PER_SECOND);
182199
}
183200
}
184201

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