-
-
Notifications
You must be signed in to change notification settings - Fork 127
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
ExtEvLoop: Add new ExtEvLoop (PECL source ext-ev) #12
Changes from all commits
6241c0e
8e847ea
b2b68c6
a496c63
e21c0ab
804d13c
126a6bd
8d12457
1cf5df8
e5b0a0b
34b51b6
5a643f2
7edb3b8
39aff0d
b616955
a643c7a
f01422d
40127e4
f8309da
525d1cf
9edc3f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
composer.lock | ||
phpunit.xml | ||
vendor |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
<?php | ||
|
||
namespace React\EventLoop; | ||
|
||
use SplObjectStorage; | ||
use React\EventLoop\Timer\Timer; | ||
use React\EventLoop\Timer\TimerInterface; | ||
use React\EventLoop\Tick\FutureTickQueue; | ||
use React\EventLoop\Tick\NextTickQueue; | ||
|
||
class ExtEvLoop implements LoopInterface | ||
{ | ||
private $loop; | ||
private $nextTickQueue; | ||
private $futureTickQueue; | ||
private $timers; | ||
private $readEvents = array(); | ||
private $writeEvents = array(); | ||
|
||
private $running = false; | ||
|
||
public function __construct() | ||
{ | ||
$this->loop = new \EvLoop(); | ||
$this->timers = new SplObjectStorage(); | ||
$this->nextTickQueue = new NextTickQueue($this); | ||
$this->futureTickQueue = new FutureTickQueue($this); | ||
$this->timers = new SplObjectStorage(); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addReadStream($stream, callable $listener) | ||
{ | ||
$this->addStream($stream, $listener, \Ev::READ); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addWriteStream($stream, callable $listener) | ||
{ | ||
$this->addStream($stream, $listener, \Ev::WRITE); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeReadStream($stream) | ||
{ | ||
$key = (int) $stream; | ||
if (isset($this->readEvents[$key])) { | ||
$this->readEvents[$key]->stop(); | ||
unset($this->readEvents[$key]); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeWriteStream($stream) | ||
{ | ||
$key = (int) $stream; | ||
if (isset($this->writeEvents[$key])) { | ||
$this->writeEvents[$key]->stop(); | ||
unset($this->writeEvents[$key]); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function removeStream($stream) | ||
{ | ||
$this->removeReadStream($stream); | ||
$this->removeWriteStream($stream); | ||
} | ||
|
||
/** | ||
* Wraps the listener in a callback which will pass the | ||
* stream to the listener then registers the stream with | ||
* the eventloop. | ||
* | ||
* @param resource $stream PHP Stream resource | ||
* @param callable $listener stream callback | ||
* @param int $flags flag bitmask | ||
*/ | ||
private function addStream($stream, callable $listener, $flags) | ||
{ | ||
$listener = function ($event) use ($stream, $listener) { | ||
call_user_func($listener, $stream, $this); | ||
}; | ||
|
||
$event = $this->loop->io($stream, $flags, $listener); | ||
|
||
if (($flags & \Ev::READ) === $flags) { | ||
$this->readEvents[(int)$stream] = $event; | ||
} elseif (($flags & \Ev::WRITE) === $flags) { | ||
$this->writeEvents[(int)$stream] = $event; | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addTimer($interval, callable $callback) | ||
{ | ||
$timer = new Timer($this, $interval, $callback, false); | ||
$this->setupTimer($timer); | ||
|
||
return $timer; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function addPeriodicTimer($interval, callable $callback) | ||
{ | ||
$timer = new Timer($this, $interval, $callback, true); | ||
$this->setupTimer($timer); | ||
|
||
return $timer; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function cancelTimer(TimerInterface $timer) | ||
{ | ||
if (isset($this->timers[$timer])) { | ||
/* stop EvTimer */ | ||
$this->timers[$timer]->stop(); | ||
|
||
/* defer timer */ | ||
$this->nextTick(function() use ($timer) { | ||
$this->timers->detach($timer); | ||
}); | ||
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. hey, this defer was added to work around a segfault, right? is it still needed? |
||
} | ||
} | ||
|
||
/** | ||
* Add timer object as | ||
* @param TimerInterface $timer [description] | ||
* @return [type] [description] | ||
*/ | ||
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. Missing something here? :-) Seems incomplete.... 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. Looks ok to me, what strikes you as incomplete? There are some work arounds necessary with the EV extension in order to avoid segfaults across different versions of PHP, this is what your seeing here. 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. Hah sorry, I mean the contents of the phpdoc block :-) 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. Hah, missed that - i'll get that updated accordingly |
||
private function setupTimer(TimerInterface $timer) | ||
{ | ||
$callback = function () use ($timer) { | ||
call_user_func($timer->getCallback(), $timer); | ||
|
||
if (!$timer->isPeriodic()) { | ||
$timer->cancel(); | ||
} | ||
}; | ||
|
||
$interval = $timer->getInterval(); | ||
|
||
$libevTimer = $this->loop->timer($interval, $interval, $callback); | ||
|
||
$this->timers->attach($timer, $libevTimer); | ||
|
||
return $timer; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function isTimerActive(TimerInterface $timer) | ||
{ | ||
return $this->timers->contains($timer); | ||
} | ||
|
||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function nextTick(callable $listener) | ||
{ | ||
$this->nextTickQueue->add($listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function futureTick(callable $listener) | ||
{ | ||
$this->futureTickQueue->add($listener); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function tick() | ||
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. Missing phpdoc headers with |
||
{ | ||
$this->nextTickQueue->tick(); | ||
$this->futureTickQueue->tick(); | ||
|
||
$flags = \Ev::RUN_ONCE; | ||
if (!$this->running || !$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) { | ||
$flags |= \Ev::RUN_NOWAIT; | ||
} elseif (!$this->readEvents && !$this->writeEvents && !$this->timers->count()) { | ||
$this->running = false; | ||
return; | ||
} | ||
$this->loop->run($flags); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function run() | ||
{ | ||
$this->running = true; | ||
|
||
while($this->running) { | ||
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. I'd put an empty line before this |
||
$this->tick(); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function stop() | ||
{ | ||
$this->running = false; | ||
} | ||
|
||
public function __destruct() | ||
{ | ||
// mannually stop all watchers | ||
foreach ($this->timers as $timer) { | ||
$this->timers[$timer]->stop(); | ||
} | ||
|
||
foreach ($this->readEvents as $event) { | ||
$event->stop(); | ||
} | ||
|
||
foreach ($this->writeEvents as $event) { | ||
$event->stop(); | ||
} | ||
} | ||
} |
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.
You should use
@inheritdoc
for the phpdoc headers of methods defined in theReact\EventLoop\LoopInterface
.