2
2
3
3
namespace React \EventLoop ;
4
4
5
- use SplObjectStorage ;
5
+ use libev \EventLoop ;
6
+ use libev \IOEvent ;
7
+ use libev \TimerEvent ;
8
+ use React \EventLoop \Tick \NextTickQueue ;
6
9
use React \EventLoop \Timer \Timer ;
7
10
use React \EventLoop \Timer \TimerInterface ;
11
+ use SplObjectStorage ;
8
12
9
13
/**
10
14
* @see https://github.com/m4rw3r/php-libev
13
17
class LibEvLoop implements LoopInterface
14
18
{
15
19
private $ loop ;
20
+ private $ nextTickQueue ;
16
21
private $ timers ;
17
22
private $ readEvents = array ();
18
23
private $ writeEvents = array ();
24
+ private $ running ;
19
25
20
26
public function __construct ()
21
27
{
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 ;
24
31
}
25
32
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
+ */
26
39
public function addReadStream ($ stream , $ listener )
27
40
{
28
- $ this ->addStream ($ stream , $ listener , \ libev \ IOEvent::READ );
41
+ $ this ->addStream ($ stream , $ listener , IOEvent::READ );
29
42
}
30
43
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
+ */
31
50
public function addWriteStream ($ stream , $ listener )
32
51
{
33
- $ this ->addStream ($ stream , $ listener , \ libev \ IOEvent::WRITE );
52
+ $ this ->addStream ($ stream , $ listener , IOEvent::WRITE );
34
53
}
35
54
55
+ /**
56
+ * Remove the read event listener for the given stream.
57
+ *
58
+ * @param stream $stream The PHP stream resource.
59
+ */
36
60
public function removeReadStream ($ stream )
37
61
{
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 ]);
41
65
}
42
66
}
43
67
68
+ /**
69
+ * Remove the write event listener for the given stream.
70
+ *
71
+ * @param stream $stream The PHP stream resource.
72
+ */
44
73
public function removeWriteStream ($ stream )
45
74
{
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 ]);
49
78
}
50
79
}
51
80
81
+ /**
82
+ * Remove all listeners for the given stream.
83
+ *
84
+ * @param stream $stream The PHP stream resource.
85
+ */
52
86
public function removeStream ($ stream )
53
87
{
54
88
$ this ->removeReadStream ($ stream );
55
89
$ this ->removeWriteStream ($ stream );
56
90
}
57
91
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
+
58
155
/**
59
156
* Schedule a callback to be invoked on the next tick of the event loop.
60
157
*
@@ -65,57 +162,74 @@ public function removeStream($stream)
65
162
*/
66
163
public function nextTick (callable $ listener )
67
164
{
68
- throw new \ Exception ( ' Not yet implemented. ' );
165
+ $ this -> nextTickQueue -> add ( $ listener );
69
166
}
70
167
71
- private function addStream ($ stream , $ listener , $ flags )
168
+ /**
169
+ * Perform a single iteration of the event loop.
170
+ */
171
+ public function tick ()
72
172
{
73
- $ listener = $ this ->wrapStreamListener ($ stream , $ listener , $ flags );
74
- $ event = new \libev \IOEvent ($ listener , $ stream , $ flags );
75
- $ this ->loop ->add ($ event );
173
+ $ this ->nextTickQueue ->tick ();
76
174
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 );
82
176
}
83
177
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 ()
85
182
{
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 ;
91
184
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
+ }
95
199
}
96
200
97
- public function addTimer ($ interval , $ callback )
201
+ /**
202
+ * Instruct a running event loop to stop.
203
+ */
204
+ public function stop ()
98
205
{
99
- $ timer = new Timer ($ this , $ interval , $ callback , false );
100
- $ this ->setupTimer ($ timer );
101
-
102
- return $ timer ;
206
+ $ this ->running = false ;
103
207
}
104
208
105
- public function addPeriodicTimer ( $ interval , $ callback )
209
+ private function addStream ( $ stream , $ listener , $ flags )
106
210
{
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 );
109
214
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
+ }
111
220
}
112
221
113
- public function cancelTimer ( TimerInterface $ timer )
222
+ private function wrapStreamListener ( $ stream , $ listener , $ flags )
114
223
{
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 ' );
118
228
}
229
+
230
+ return function ($ event ) use ($ stream , $ listener , $ removeCallback ) {
231
+ call_user_func ($ listener , $ stream );
232
+ };
119
233
}
120
234
121
235
private function setupTimer (TimerInterface $ timer )
@@ -124,9 +238,9 @@ private function setupTimer(TimerInterface $timer)
124
238
$ interval = $ timer ->getInterval ();
125
239
126
240
if ($ timer ->isPeriodic ()) {
127
- $ libevTimer = new \ libev \ TimerEvent ($ dummyCallback , $ interval , $ interval );
241
+ $ libevTimer = new TimerEvent ($ dummyCallback , $ interval , $ interval );
128
242
} else {
129
- $ libevTimer = new \ libev \ TimerEvent ($ dummyCallback , $ interval );
243
+ $ libevTimer = new TimerEvent ($ dummyCallback , $ interval );
130
244
}
131
245
132
246
$ libevTimer ->setCallback (function () use ($ timer ) {
@@ -142,24 +256,4 @@ private function setupTimer(TimerInterface $timer)
142
256
143
257
return $ timer ;
144
258
}
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
- }
165
259
}
0 commit comments