-
-
Notifications
You must be signed in to change notification settings - Fork 727
Implemented some experimental event loops with nextTick() support. #234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
db41311
cbe3664
f0fb0af
abbb05d
75b496a
35e4cd0
7fac0d3
514d05b
85d0bcc
93da5ec
dc43f53
a8af7bc
18a00c7
3bba9e4
74131f7
17c378f
7d7dd65
a8fe3cf
0ac0305
3ac92ee
87d2207
cae3165
c0cd613
edc337e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
* ExtEventLoop - based on the ext-event PHP extension * StreamSelectNextTickLoop - based on stream_select
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<?php | ||
|
||
namespace React\EventLoop; | ||
|
||
use React\EventLoop\Timer\Timer; | ||
use React\EventLoop\Timer\TimerInterface; | ||
use SplQueue; | ||
|
||
/** | ||
* Common functionality for event loops that implement NextTickLoopInterface. | ||
*/ | ||
abstract class AbstractNextTickLoop implements NextTickLoopInterface | ||
{ | ||
private $nextTickQueue; | ||
private $explicitlyStopped; | ||
|
||
public function __construct() | ||
{ | ||
$this->nextTickQueue = new SplQueue; | ||
$this->explicitlyStopped = false; | ||
} | ||
|
||
/** | ||
* Enqueue a callback to be invoked once after the given interval. | ||
* | ||
* The execution order of timers scheduled to execute at the same time is | ||
* not guaranteed. | ||
* | ||
* @param numeric $interval The number of seconds to wait before execution. | ||
* @param callable $callback The callback to invoke. | ||
* | ||
* @return TimerInterface | ||
*/ | ||
public function addTimer($interval, $callback) | ||
{ | ||
$timer = new Timer($this, $interval, $callback, false); | ||
|
||
$this->scheduleTimer($timer); | ||
|
||
return $timer; | ||
} | ||
|
||
/** | ||
* Enqueue a callback to be invoked repeatedly after the given interval. | ||
* | ||
* The execution order of timers scheduled to execute at the same time is | ||
* not guaranteed. | ||
* | ||
* @param numeric $interval The number of seconds to wait before execution. | ||
* @param callable $callback The callback to invoke. | ||
* | ||
* @return TimerInterface | ||
*/ | ||
public function addPeriodicTimer($interval, $callback) | ||
{ | ||
$timer = new Timer($this, $interval, $callback, true); | ||
|
||
$this->scheduleTimer($timer); | ||
|
||
return $timer; | ||
} | ||
|
||
/** | ||
* Schedule a callback to be invoked on the next tick of the event loop. | ||
* | ||
* Callbacks are guaranteed to be executed in the order they are enqueued, | ||
* before any timer or stream events. | ||
* | ||
* @param callable $listner The callback to invoke. | ||
*/ | ||
public function nextTick(callable $listener) | ||
{ | ||
$this->nextTickQueue->enqueue($listener); | ||
} | ||
|
||
/** | ||
* Perform a single iteration of the event loop. | ||
*/ | ||
public function tick() | ||
{ | ||
$this->tickLogic(false); | ||
} | ||
|
||
/** | ||
* Run the event loop until there are no more tasks to perform. | ||
*/ | ||
public function run() | ||
{ | ||
$this->explicitlyStopped = false; | ||
|
||
while ($this->isRunning()) { | ||
$this->tickLogic(true); | ||
} | ||
} | ||
|
||
/** | ||
* Instruct a running event loop to stop. | ||
*/ | ||
public function stop() | ||
{ | ||
$this->explicitlyStopped = true; | ||
} | ||
|
||
/** | ||
* Invoke all callbacks in the next-tick queue. | ||
*/ | ||
protected function flushNextTickQueue() | ||
{ | ||
while ($this->nextTickQueue->count()) { | ||
call_user_func( | ||
$this->nextTickQueue->dequeue(), | ||
$this | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Check if there is any pending work to do. | ||
* | ||
* @return boolean | ||
*/ | ||
protected function isRunning() | ||
{ | ||
// The loop has been explicitly stopped and should exit ... | ||
if ($this->explicitlyStopped) { | ||
return false; | ||
|
||
// The next tick queue has items on it ... | ||
} elseif ($this->nextTickQueue->count() > 0) { | ||
return true; | ||
} | ||
|
||
return !$this->isEmpty(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seriously nitpicking here, but I think the logic behind That's one reason why I don't like much the strictness an abstract class enforces upon us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah it needed a better name, but ... the abstract class has been removed entirely in the most recent push :) |
||
} | ||
|
||
/** | ||
* Perform the low-level tick logic. | ||
*/ | ||
protected function tickLogic($blocking) | ||
{ | ||
$this->flushNextTickQueue(); | ||
|
||
$this->flushEvents( | ||
$blocking && 0 === $this->nextTickQueue->count() | ||
); | ||
} | ||
|
||
/** | ||
* Get a key that can be used to identify a stream resource. | ||
* | ||
* @param string $stream | ||
* | ||
* @return integer|string | ||
*/ | ||
protected function streamKey($stream) | ||
{ | ||
return (int) $stream; | ||
} | ||
|
||
/** | ||
* Schedule a timer for execution. | ||
* | ||
* @param TimerInterface $timer | ||
*/ | ||
abstract protected function scheduleTimer(TimerInterface $timer); | ||
|
||
/** | ||
* Flush any timer and IO events. | ||
* | ||
* @param boolean $blocking True if loop should block waiting for next event. | ||
*/ | ||
abstract protected function flushEvents($blocking); | ||
|
||
/** | ||
* Check if the loop has any pending timers or streams. | ||
* | ||
* @return boolean | ||
*/ | ||
abstract protected function isEmpty(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just
$stop
would do, IMHO.