Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 130
PeclEvLoop: Add new PeclEvLoop (PECL ext-ev)#97
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
4455a3b051a4a30b375f73391da50e56b44316e6a94c70da03ae182952e5e2e539203245b7ab042bc95ddac7c4141d9d632ef8ff054710a379dd25cFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| <?php | ||
| namespace React\EventLoop; | ||
| use Ev; | ||
| use EvLoop; | ||
| use React\EventLoop\Tick\FutureTickQueue; | ||
| use React\EventLoop\Timer\Timer; | ||
| use React\EventLoop\Timer\TimerInterface; | ||
| use SplObjectStorage; | ||
| /** | ||
| * @see https://bitbucket.org/osmanov/pecl-ev/overview | ||
| */ | ||
| class PeclEvLoop implements LoopInterface | ||
| { | ||
| private $loop; | ||
| private $futureTickQueue; | ||
| private $timers; | ||
| private $readStreams = []; | ||
| private $writeStreams = []; | ||
| private $running; | ||
| public function __construct() | ||
| { | ||
| $this->loop = new EvLoop(); | ||
| $this->futureTickQueue = new FutureTickQueue($this); | ||
| $this->timers = new SplObjectStorage(); | ||
| } | ||
| public function addReadStream($stream, callable $listener) | ||
| { | ||
| $key = (int) $stream; | ||
| if (isset($this->readStreams[$key])) { | ||
| return; | ||
| } | ||
| $callback = $this->getStreamListenerClosure($stream, $listener); | ||
| $event = $this->loop->io($stream, Ev::READ, $callback); | ||
| $this->readStreams[$key] = $event; | ||
| } | ||
| /** | ||
| * @param resource $stream | ||
| * @param callable $listener | ||
| * | ||
| * @return \Closure | ||
| */ | ||
| private function getStreamListenerClosure($stream, callable $listener) { | ||
Member 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. Minor nitpick: Line break before | ||
| return function () use ($stream, $listener) { | ||
| call_user_func($listener, $stream, $this); | ||
| }; | ||
| } | ||
| public function addWriteStream($stream, callable $listener) | ||
| { | ||
| $key = (int) $stream; | ||
| if (isset($this->writeStreams[$key])) { | ||
| return; | ||
| } | ||
| $callback = $this->getStreamListenerClosure($stream, $listener); | ||
| $event = $this->loop->io($stream, Ev::WRITE, $callback); | ||
| $this->writeStreams[$key] = $event; | ||
| } | ||
| public function removeReadStream($stream) | ||
| { | ||
| $key = (int) $stream; | ||
| if (!isset($this->readStreams[$key])) { | ||
| return; | ||
| } | ||
| $this->readStreams[$key]->stop(); | ||
| unset($this->readStreams[$key]); | ||
| } | ||
| public function removeWriteStream($stream) | ||
| { | ||
| $key = (int) $stream; | ||
| if (!isset($this->writeStreams[$key])) { | ||
| return; | ||
| } | ||
| $this->writeStreams[$key]->stop(); | ||
| unset($this->writeStreams[$key]); | ||
| } | ||
| public function removeStream($stream) | ||
| { | ||
| $this->removeReadStream($stream); | ||
| $this->removeWriteStream($stream); | ||
| } | ||
| public function addTimer($interval, callable $callback) | ||
| { | ||
| $timer = new Timer($this, $interval, $callback, false); | ||
| $callback = function () use ($timer) { | ||
| call_user_func($timer->getCallback(), $timer); | ||
| if ($this->isTimerActive($timer)) { | ||
| $this->cancelTimer($timer); | ||
| } | ||
| }; | ||
| $event = $this->loop->timer($timer->getInterval(), 0.0, $callback); | ||
| $this->timers->attach($timer, $event); | ||
| return $timer; | ||
| } | ||
| public function addPeriodicTimer($interval, callable $callback) | ||
| { | ||
| $timer = new Timer($this, $interval, $callback, true); | ||
| $callback = function () use ($timer) { | ||
| call_user_func($timer->getCallback(), $timer); | ||
| }; | ||
| //reschedule callback should be NULL to utilize $offset and $interval params | ||
| $event = $this->loop->periodic($interval, $interval, NULL, $callback); | ||
| $this->timers->attach($timer, $event); | ||
| return $timer; | ||
| } | ||
| public function cancelTimer(TimerInterface $timer) | ||
| { | ||
| if (!isset($this->timers[$timer])) { | ||
| return; | ||
| } | ||
| $event = $this->timers[$timer]; | ||
| $event->stop(); | ||
| $this->timers->detach($timer); | ||
| } | ||
| public function isTimerActive(TimerInterface $timer) | ||
| { | ||
| return $this->timers->contains($timer); | ||
| } | ||
| public function futureTick(callable $listener) | ||
| { | ||
| $this->futureTickQueue->add($listener); | ||
| } | ||
| public function run() | ||
| { | ||
| $this->running = true; | ||
| while ($this->running) { | ||
| $this->futureTickQueue->tick(); | ||
| $hasPendingCallbacks = !$this->futureTickQueue->isEmpty(); | ||
| $wasJustStopped = !$this->running; | ||
| $nothingLeftToDo = !$this->readStreams && !$this->writeStreams && !$this->timers->count(); | ||
| $flags = Ev::RUN_ONCE; | ||
| if ($wasJustStopped || $hasPendingCallbacks) { | ||
| $flags |= Ev::RUN_NOWAIT; | ||
| } elseif ($nothingLeftToDo) { | ||
| break; | ||
| } | ||
| $this->loop->run($flags); | ||
| } | ||
| } | ||
| public function stop() | ||
| { | ||
| $this->running = false; | ||
| } | ||
| public function __destruct() | ||
| { | ||
| /** @var TimerInterface $timer */ | ||
| foreach($this->timers as $timer) { | ||
| $this->cancelTimer($timer); | ||
| } | ||
| foreach($this->readStreams as $key => $stream) { | ||
| $this->removeReadStream($key); | ||
| } | ||
| foreach($this->writeStreams as $key => $stream) { | ||
| $this->removeWriteStream($key); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?php | ||
| namespace React\Tests\EventLoop; | ||
| use React\EventLoop\PeclEvLoop; | ||
| class PeclEvLoopTest extends AbstractLoopTest | ||
| { | ||
| public function createLoop() | ||
| { | ||
| if (!class_exists('EvLoop')) { | ||
| $this->markTestSkipped('pecl-ev tests skipped because ext-ev is not installed.'); | ||
| } | ||
| return new PeclEvLoop(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?php | ||
| namespace React\Tests\EventLoop\Timer; | ||
| use React\EventLoop\PeclEvLoop; | ||
| class PeclEvLoopTimerTest extends AbstractTimerTest | ||
| { | ||
| public function createLoop() | ||
| { | ||
| if (!class_exists('EvLoop')) { | ||
| $this->markTestSkipped('pecl-ev tests skipped because ext-ev is not installed.'); | ||
| } | ||
| return new PeclEvLoop(); | ||
| } | ||
| } |
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.
A short description would help?