Skip to content

Commit 61d8596

Browse files
committed
Added nextTick() support to LibEvLoop.
1 parent 7185d3b commit 61d8596

File tree

1 file changed

+159
-65
lines changed

1 file changed

+159
-65
lines changed

LibEvLoop.php

Lines changed: 159 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
namespace React\EventLoop;
44

5-
use SplObjectStorage;
5+
use libev\EventLoop;
6+
use libev\IOEvent;
7+
use libev\TimerEvent;
8+
use React\EventLoop\Tick\NextTickQueue;
69
use React\EventLoop\Timer\Timer;
710
use React\EventLoop\Timer\TimerInterface;
11+
use SplObjectStorage;
812

913
/**
1014
* @see https://github.com/m4rw3r/php-libev
@@ -13,48 +17,141 @@
1317
class LibEvLoop implements LoopInterface
1418
{
1519
private $loop;
20+
private $nextTickQueue;
1621
private $timers;
1722
private $readEvents = array();
1823
private $writeEvents = array();
24+
private $running;
1925

2026
public function __construct()
2127
{
22-
$this->loop = new \libev\EventLoop();
23-
$this->timers = new SplObjectStorage();
28+
$this->loop = new EventLoop;
29+
$this->nextTickQueue = new NextTickQueue($this);
30+
$this->timers = new SplObjectStorage;
2431
}
2532

33+
/**
34+
* Register a listener to be notified when a stream is ready to read.
35+
*
36+
* @param stream $stream The PHP stream resource to check.
37+
* @param callable $listener Invoked when the stream is ready.
38+
*/
2639
public function addReadStream($stream, $listener)
2740
{
28-
$this->addStream($stream, $listener, \libev\IOEvent::READ);
41+
$this->addStream($stream, $listener, IOEvent::READ);
2942
}
3043

44+
/**
45+
* Register a listener to be notified when a stream is ready to write.
46+
*
47+
* @param stream $stream The PHP stream resource to check.
48+
* @param callable $listener Invoked when the stream is ready.
49+
*/
3150
public function addWriteStream($stream, $listener)
3251
{
33-
$this->addStream($stream, $listener, \libev\IOEvent::WRITE);
52+
$this->addStream($stream, $listener, IOEvent::WRITE);
3453
}
3554

55+
/**
56+
* Remove the read event listener for the given stream.
57+
*
58+
* @param stream $stream The PHP stream resource.
59+
*/
3660
public function removeReadStream($stream)
3761
{
38-
if (isset($this->readEvents[(int)$stream])) {
39-
$this->readEvents[(int)$stream]->stop();
40-
unset($this->readEvents[(int)$stream]);
62+
if (isset($this->readEvents[(int) $stream])) {
63+
$this->readEvents[(int) $stream]->stop();
64+
unset($this->readEvents[(int) $stream]);
4165
}
4266
}
4367

68+
/**
69+
* Remove the write event listener for the given stream.
70+
*
71+
* @param stream $stream The PHP stream resource.
72+
*/
4473
public function removeWriteStream($stream)
4574
{
46-
if (isset($this->writeEvents[(int)$stream])) {
47-
$this->writeEvents[(int)$stream]->stop();
48-
unset($this->writeEvents[(int)$stream]);
75+
if (isset($this->writeEvents[(int) $stream])) {
76+
$this->writeEvents[(int) $stream]->stop();
77+
unset($this->writeEvents[(int) $stream]);
4978
}
5079
}
5180

81+
/**
82+
* Remove all listeners for the given stream.
83+
*
84+
* @param stream $stream The PHP stream resource.
85+
*/
5286
public function removeStream($stream)
5387
{
5488
$this->removeReadStream($stream);
5589
$this->removeWriteStream($stream);
5690
}
5791

92+
/**
93+
* Enqueue a callback to be invoked once after the given interval.
94+
*
95+
* The execution order of timers scheduled to execute at the same time is
96+
* not guaranteed.
97+
*
98+
* @param numeric $interval The number of seconds to wait before execution.
99+
* @param callable $callback The callback to invoke.
100+
*
101+
* @return TimerInterface
102+
*/
103+
public function addTimer($interval, $callback)
104+
{
105+
$timer = new Timer($this, $interval, $callback, false);
106+
$this->setupTimer($timer);
107+
108+
return $timer;
109+
}
110+
111+
/**
112+
* Enqueue a callback to be invoked repeatedly after the given interval.
113+
*
114+
* The execution order of timers scheduled to execute at the same time is
115+
* not guaranteed.
116+
*
117+
* @param numeric $interval The number of seconds to wait before execution.
118+
* @param callable $callback The callback to invoke.
119+
*
120+
* @return TimerInterface
121+
*/
122+
public function addPeriodicTimer($interval, $callback)
123+
{
124+
$timer = new Timer($this, $interval, $callback, true);
125+
$this->setupTimer($timer);
126+
127+
return $timer;
128+
}
129+
130+
/**
131+
* Cancel a pending timer.
132+
*
133+
* @param TimerInterface $timer The timer to cancel.
134+
*/
135+
public function cancelTimer(TimerInterface $timer)
136+
{
137+
if (isset($this->timers[$timer])) {
138+
$this->loop->remove($this->timers[$timer]);
139+
$this->timers->detach($timer);
140+
}
141+
}
142+
143+
/**
144+
* Check if a given timer is active.
145+
*
146+
* @param TimerInterface $timer The timer to check.
147+
*
148+
* @return boolean True if the timer is still enqueued for execution.
149+
*/
150+
public function isTimerActive(TimerInterface $timer)
151+
{
152+
return $this->timers->contains($timer);
153+
}
154+
58155
/**
59156
* Schedule a callback to be invoked on the next tick of the event loop.
60157
*
@@ -65,57 +162,74 @@ public function removeStream($stream)
65162
*/
66163
public function nextTick(callable $listener)
67164
{
68-
throw new \Exception('Not yet implemented.');
165+
$this->nextTickQueue->add($listener);
69166
}
70167

71-
private function addStream($stream, $listener, $flags)
168+
/**
169+
* Perform a single iteration of the event loop.
170+
*/
171+
public function tick()
72172
{
73-
$listener = $this->wrapStreamListener($stream, $listener, $flags);
74-
$event = new \libev\IOEvent($listener, $stream, $flags);
75-
$this->loop->add($event);
173+
$this->nextTickQueue->tick();
76174

77-
if (($flags & \libev\IOEvent::READ) === $flags) {
78-
$this->readEvents[(int)$stream] = $event;
79-
} elseif (($flags & \libev\IOEvent::WRITE) === $flags) {
80-
$this->writeEvents[(int)$stream] = $event;
81-
}
175+
$this->loop->run(EventLoop::RUN_ONCE | EventLoop::RUN_NOWAIT);
82176
}
83177

84-
private function wrapStreamListener($stream, $listener, $flags)
178+
/**
179+
* Run the event loop until there are no more tasks to perform.
180+
*/
181+
public function run()
85182
{
86-
if (($flags & \libev\IOEvent::READ) === $flags) {
87-
$removeCallback = array($this, 'removeReadStream');
88-
} elseif (($flags & \libev\IOEvent::WRITE) === $flags) {
89-
$removeCallback = array($this, 'removeWriteStream');
90-
}
183+
$this->running = true;
91184

92-
return function ($event) use ($stream, $listener, $removeCallback) {
93-
call_user_func($listener, $stream);
94-
};
185+
while ($this->running) {
186+
187+
$this->nextTickQueue->tick();
188+
189+
if (
190+
!$this->readEvents
191+
&& !$this->writeEvents
192+
&& !$this->timers->count()
193+
) {
194+
break;
195+
}
196+
197+
$this->loop->run(EventLoop::RUN_ONCE);
198+
}
95199
}
96200

97-
public function addTimer($interval, $callback)
201+
/**
202+
* Instruct a running event loop to stop.
203+
*/
204+
public function stop()
98205
{
99-
$timer = new Timer($this, $interval, $callback, false);
100-
$this->setupTimer($timer);
101-
102-
return $timer;
206+
$this->running = false;
103207
}
104208

105-
public function addPeriodicTimer($interval, $callback)
209+
private function addStream($stream, $listener, $flags)
106210
{
107-
$timer = new Timer($this, $interval, $callback, true);
108-
$this->setupTimer($timer);
211+
$listener = $this->wrapStreamListener($stream, $listener, $flags);
212+
$event = new IOEvent($listener, $stream, $flags);
213+
$this->loop->add($event);
109214

110-
return $timer;
215+
if (($flags & IOEvent::READ) === $flags) {
216+
$this->readEvents[(int) $stream] = $event;
217+
} elseif (($flags & IOEvent::WRITE) === $flags) {
218+
$this->writeEvents[(int) $stream] = $event;
219+
}
111220
}
112221

113-
public function cancelTimer(TimerInterface $timer)
222+
private function wrapStreamListener($stream, $listener, $flags)
114223
{
115-
if (isset($this->timers[$timer])) {
116-
$this->loop->remove($this->timers[$timer]);
117-
$this->timers->detach($timer);
224+
if (($flags & IOEvent::READ) === $flags) {
225+
$removeCallback = array($this, 'removeReadStream');
226+
} elseif (($flags & IOEvent::WRITE) === $flags) {
227+
$removeCallback = array($this, 'removeWriteStream');
118228
}
229+
230+
return function ($event) use ($stream, $listener, $removeCallback) {
231+
call_user_func($listener, $stream);
232+
};
119233
}
120234

121235
private function setupTimer(TimerInterface $timer)
@@ -124,9 +238,9 @@ private function setupTimer(TimerInterface $timer)
124238
$interval = $timer->getInterval();
125239

126240
if ($timer->isPeriodic()) {
127-
$libevTimer = new \libev\TimerEvent($dummyCallback, $interval, $interval);
241+
$libevTimer = new TimerEvent($dummyCallback, $interval, $interval);
128242
} else {
129-
$libevTimer = new \libev\TimerEvent($dummyCallback, $interval);
243+
$libevTimer = new TimerEvent($dummyCallback, $interval);
130244
}
131245

132246
$libevTimer->setCallback(function () use ($timer) {
@@ -142,24 +256,4 @@ private function setupTimer(TimerInterface $timer)
142256

143257
return $timer;
144258
}
145-
146-
public function isTimerActive(TimerInterface $timer)
147-
{
148-
return $this->timers->contains($timer);
149-
}
150-
151-
public function tick()
152-
{
153-
$this->loop->run(\libev\EventLoop::RUN_ONCE);
154-
}
155-
156-
public function run()
157-
{
158-
$this->loop->run();
159-
}
160-
161-
public function stop()
162-
{
163-
$this->loop->breakLoop();
164-
}
165259
}

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