2
2
3
3
namespace React \EventLoop ;
4
4
5
- use Exception ;
6
5
use React \EventLoop \Timer \Timer ;
7
6
use React \EventLoop \Timer \TimerInterface ;
8
- use SplObjectStorage ;
9
- use SplPriorityQueue ;
10
- use SplQueue ;
7
+ use React \EventLoop \Timer \Timers ;
11
8
12
9
/**
13
10
* A stream_select() based event-loop with support for nextTick().
@@ -18,13 +15,11 @@ class StreamSelectNextTickLoop extends AbstractNextTickLoop
18
15
private $ readListeners = [];
19
16
private $ writeStreams = [];
20
17
private $ writeListeners = [];
21
- private $ timerQueue ;
22
- private $ timerTimestamps ;
18
+ private $ timers ;
23
19
24
20
public function __construct ()
25
21
{
26
- $ this ->timerQueue = new SplPriorityQueue ;
27
- $ this ->timerTimestamps = new SplObjectStorage ;
22
+ $ this ->timers = new Timers ;
28
23
29
24
parent ::__construct ();
30
25
}
@@ -102,14 +97,52 @@ public function removeStream($stream)
102
97
$ this ->removeWriteStream ($ stream );
103
98
}
104
99
100
+ /**
101
+ * Enqueue a callback to be invoked once after the given interval.
102
+ *
103
+ * The execution order of timers scheduled to execute at the same time is
104
+ * not guaranteed.
105
+ *
106
+ * @param numeric $interval The number of seconds to wait before execution.
107
+ * @param callable $callback The callback to invoke.
108
+ *
109
+ * @return TimerInterface
110
+ */
111
+ public function addTimer ($ interval , $ callback )
112
+ {
113
+ $ timer = new Timer ($ this , $ interval , $ callback , false );
114
+ $ this ->timers ->add ($ timer );
115
+
116
+ return $ timer ;
117
+ }
118
+
119
+ /**
120
+ * Enqueue a callback to be invoked repeatedly after the given interval.
121
+ *
122
+ * The execution order of timers scheduled to execute at the same time is
123
+ * not guaranteed.
124
+ *
125
+ * @param numeric $interval The number of seconds to wait before execution.
126
+ * @param callable $callback The callback to invoke.
127
+ *
128
+ * @return TimerInterface
129
+ */
130
+ public function addPeriodicTimer ($ interval , $ callback )
131
+ {
132
+ $ timer = new Timer ($ this , $ interval , $ callback , true );
133
+ $ this ->timers ->add ($ timer );
134
+
135
+ return $ timer ;
136
+ }
137
+
105
138
/**
106
139
* Cancel a pending timer.
107
140
*
108
141
* @param TimerInterface $timer The timer to cancel.
109
142
*/
110
143
public function cancelTimer (TimerInterface $ timer )
111
144
{
112
- $ this ->timerTimestamps -> detach ($ timer );
145
+ $ this ->timers -> cancel ($ timer );
113
146
}
114
147
115
148
/**
@@ -121,7 +154,7 @@ public function cancelTimer(TimerInterface $timer)
121
154
*/
122
155
public function isTimerActive (TimerInterface $ timer )
123
156
{
124
- return $ this ->timerTimestamps ->contains ($ timer );
157
+ return $ this ->timers ->contains ($ timer );
125
158
}
126
159
127
160
/**
@@ -131,7 +164,7 @@ public function isTimerActive(TimerInterface $timer)
131
164
*/
132
165
protected function flushEvents ($ blocking )
133
166
{
134
- $ this ->flushTimerQueue ();
167
+ $ this ->timers -> tick ();
135
168
$ this ->waitForStreamActivity ($ blocking );
136
169
}
137
170
@@ -142,7 +175,7 @@ protected function flushEvents($blocking)
142
175
*/
143
176
protected function isEmpty ()
144
177
{
145
- return 0 === count ( $ this ->timerTimestamps )
178
+ return $ this ->timers -> isEmpty ( )
146
179
&& 0 === count ($ this ->readStreams )
147
180
&& 0 === count ($ this ->writeStreams );
148
181
}
@@ -175,8 +208,8 @@ protected function toMicroSeconds($seconds)
175
208
* Emulate a stream_select() implementation that does not break when passed
176
209
* empty stream arrays.
177
210
*
178
- * @param array &$read An array of read streams to select upon.
179
- * @param array &$write An array of write streams to select upon.
211
+ * @param array &$read An array of read streams to select upon.
212
+ * @param array &$write An array of write streams to select upon.
180
213
* @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
181
214
*/
182
215
protected function streamSelect (array &$ read , array &$ write , $ timeout )
@@ -198,85 +231,17 @@ protected function streamSelect(array &$read, array &$write, $timeout)
198
231
return 0 ;
199
232
}
200
233
201
- /**
202
- * Schedule a timer for execution.
203
- *
204
- * @param TimerInterface $timer
205
- */
206
- protected function scheduleTimer (TimerInterface $ timer )
207
- {
208
- $ executeAt = $ this ->now () + $ this ->toMicroSeconds (
209
- $ timer ->getInterval ()
210
- );
211
-
212
- $ this ->timerQueue ->insert ($ timer , -$ executeAt );
213
- $ this ->timerTimestamps ->attach ($ timer , $ executeAt );
214
- }
215
-
216
- /**
217
- * Get the timer next schedule to tick, if any.
218
- *
219
- * @return TimerInterface|null
220
- */
221
- protected function nextActiveTimer ()
222
- {
223
- while ($ this ->timerQueue ->count ()) {
224
- $ timer = $ this ->timerQueue ->top ();
225
-
226
- if ($ this ->isTimerActive ($ timer )) {
227
- return $ timer ;
228
- } else {
229
- $ this ->timerQueue ->extract ();
230
- }
231
- }
232
-
233
- return null ;
234
- }
235
-
236
- /**
237
- * Push callbacks for timers that are ready into the next-tick queue.
238
- */
239
- protected function flushTimerQueue ()
240
- {
241
- $ now = $ this ->now ();
242
-
243
- while ($ timer = $ this ->nextActiveTimer ()) {
244
-
245
- $ executeAt = $ this ->timerTimestamps [$ timer ];
246
-
247
- // The next time is in the future, exit the loop ...
248
- if ($ executeAt > $ now ) {
249
- break ;
250
- }
251
-
252
- $ this ->timerQueue ->extract ();
253
-
254
- call_user_func ($ timer ->getCallback (), $ timer );
255
-
256
- // Timer cancelled itself ...
257
- if (!$ this ->isTimerActive ($ timer )) {
258
- return ;
259
- // Reschedule periodic timers ...
260
- } elseif ($ timer ->isPeriodic ()) {
261
- $ this ->scheduleTimer ($ timer );
262
- // Cancel one-shot timers ...
263
- } else {
264
- $ this ->cancelTimer ($ timer );
265
- }
266
- }
267
- }
268
-
269
234
protected function waitForStreamActivity ($ blocking )
270
235
{
271
236
// The $blocking flag takes precedence ...
272
237
if (!$ blocking ) {
273
238
$ timeout = 0 ;
274
239
275
240
// There is a pending timer, only block until it is due ...
276
- } elseif ($ timer = $ this ->nextActiveTimer ()) {
241
+ } elseif ($ scheduledAt = $ this ->timers -> getFirst ()) {
277
242
$ timeout = max (
278
243
0 ,
279
- $ this -> timerTimestamps [ $ timer ] - $ this ->now ()
244
+ $ scheduledAt - $ this ->timers -> getTime ()
280
245
);
281
246
282
247
// The only possible event is stream activity, so wait forever ...
0 commit comments