diff --git a/src/ExtEvLoop.php b/src/ExtEvLoop.php new file mode 100644 index 00000000..37408feb --- /dev/null +++ b/src/ExtEvLoop.php @@ -0,0 +1,210 @@ +nextTickQueue = new NextTickQueue($this); + $this->futureTickQueue = new FutureTickQueue($this); + $this->timerEvents = new SplObjectStorage(); + } + + /** + * {@inheritdoc} + */ + public function addReadStream($stream, callable $listener) + { + $callback = function () use ($stream, $listener) { + call_user_func($listener, $stream, $this); + }; + + $event = new EvIo($stream, Ev::READ, $callback); + $this->readEvents[(int) $stream] = $event; + } + + /** + * {@inheritdoc} + */ + public function addWriteStream($stream, callable $listener) + { + $callback = function () use ($stream, $listener) { + call_user_func($listener, $stream, $this); + }; + + $event = new EvIo($stream, Ev::WRITE, $callback); + $this->writeEvents[(int) $stream] = $event; + } + + /** + * {@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); + } + + /** + * {@inheritdoc} + */ + 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 = new EvTimer($timer->getInterval(), 0, $callback); + $this->timerEvents->attach($timer, $event); + + return $timer; + } + + /** + * {@inheritdoc} + */ + public function addPeriodicTimer($interval, callable $callback) + { + $timer = new Timer($this, $interval, $callback, true); + + $callback = function () use ($timer) { + call_user_func($timer->getCallback(), $timer); + }; + + $event = new EvTimer($interval, $interval, $callback); + $this->timerEvents->attach($timer, $event); + + return $timer; + } + + /** + * {@inheritdoc} + */ + public function cancelTimer(TimerInterface $timer) + { + if (isset($this->timerEvents[$timer])) { + $this->timerEvents[$timer]->stop(); + $this->timerEvents->detach($timer); + } + } + + /** + * {@inheritdoc} + */ + public function isTimerActive(TimerInterface $timer) + { + return $this->timerEvents->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() + { + $this->nextTickQueue->tick(); + + $this->futureTickQueue->tick(); + + Ev::run(Ev::RUN_ONCE | Ev::RUN_NOWAIT); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->running = true; + + while ($this->running) { + $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->timerEvents->count()) { + break; + } + + Ev::run($flags); + } + } + + /** + * {@inheritdoc} + */ + public function stop() + { + $this->running = false; + } +} diff --git a/src/Factory.php b/src/Factory.php index 9a481e35..7f5b5f68 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -7,7 +7,9 @@ class Factory public static function create() { // @codeCoverageIgnoreStart - if (function_exists('event_base_new')) { + if (class_exists('Ev', false)) { + return new ExtEvLoop; + } elseif (function_exists('event_base_new')) { return new LibEventLoop(); } elseif (class_exists('libev\EventLoop', false)) { return new LibEvLoop;