From 8180e67f99a238e4f3e7cfdceef19fc67dcdc27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sun, 28 Jan 2024 14:08:19 +0100 Subject: [PATCH] Drop deprecated `ExtLibeventLoop` and `ExtLibevLoop` (PHP 5 only) --- .github/workflows/ci.yml | 30 +-- README.md | 42 ---- src/ExtLibevLoop.php | 201 ------------------- src/ExtLibeventLoop.php | 285 --------------------------- src/Factory.php | 9 - src/StreamSelectLoop.php | 5 +- tests/ExtLibevLoopTest.php | 22 --- tests/ExtLibeventLoopTest.php | 63 ------ tests/Timer/ExtLibevTimerTest.php | 17 -- tests/Timer/ExtLibeventTimerTest.php | 17 -- 10 files changed, 3 insertions(+), 688 deletions(-) delete mode 100644 src/ExtLibevLoop.php delete mode 100644 src/ExtLibeventLoop.php delete mode 100644 tests/ExtLibevLoopTest.php delete mode 100644 tests/ExtLibeventLoopTest.php delete mode 100644 tests/Timer/ExtLibevTimerTest.php delete mode 100644 tests/Timer/ExtLibeventTimerTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0755cde8..b4bf2b84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: PHPUnit-Unstable: name: PHPUnit (Unstable PHP ${{ matrix.php }}) - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 continue-on-error: true strategy: matrix: @@ -57,10 +57,6 @@ jobs: - 7.2 - 7.1 - 7.0 - - 5.6 - - 5.5 - - 5.4 - - 5.3 steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 @@ -74,30 +70,6 @@ jobs: sudo apt-get update -q && sudo apt-get install libuv1-dev echo "yes" | sudo pecl install ${{ matrix.php >= 8.0 && 'uv-0.3.0' || 'uv-0.2.4' }} php -m | grep -q uv || echo "extension=uv.so" >> "$(php -r 'echo php_ini_loaded_file();')" - if: ${{ matrix.php >= 7.0 }} - - name: Install legacy ext-libevent on PHP < 7.0 - run: | - sudo apt-get update && sudo apt-get install libevent-dev - curl http://pecl.php.net/get/libevent-0.1.0.tgz | tar -xz - pushd libevent-0.1.0 - phpize - ./configure - make - sudo make install - popd - echo "extension=libevent.so" | sudo tee -a "$(php -r 'echo php_ini_loaded_file();')" - if: ${{ matrix.php < 7.0 }} - - name: Install legacy ext-libev on PHP < 7.0 - run: | - git clone --recursive https://github.com/m4rw3r/php-libev - pushd php-libev - phpize - ./configure --with-libev - make - sudo make install - popd - echo "extension=libev.so" | sudo tee -a "$(php -r 'echo php_ini_loaded_file();')" - if: ${{ matrix.php < 7.0 }} - run: composer install - run: vendor/bin/phpunit --coverage-text if: ${{ matrix.php >= 7.3 }} diff --git a/README.md b/README.md index d0a197dd..93be6a57 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ single [`run()`](#run) call that is controlled by the user. * [ExtEventLoop](#exteventloop) * [ExtEvLoop](#extevloop) * [ExtUvLoop](#extuvloop) - * [~~ExtLibeventLoop~~](#extlibeventloop) - * [~~ExtLibevLoop~~](#extlibevloop) * [LoopInterface](#loopinterface) * [run()](#run) * [stop()](#stop) @@ -429,46 +427,6 @@ that provides an interface to `libuv` library. This loop is known to work with PHP 7+. -#### ~~ExtLibeventLoop~~ - -> Deprecated since v1.2.0, use [`ExtEventLoop`](#exteventloop) instead. - -An `ext-libevent` based event loop. - -This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent), -that provides an interface to `libevent` library. -`libevent` itself supports a number of system-specific backends (epoll, kqueue). - -This event loop does only work with PHP 5. -An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for -PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s. -To reiterate: Using this event loop on PHP 7 is not recommended. -Accordingly, neither the [`Loop` class](#loop) nor the deprecated -[`Factory` class](#factory) will try to use this event loop on PHP 7. - -This event loop is known to trigger a readable listener only if -the stream *becomes* readable (edge-triggered) and may not trigger if the -stream has already been readable from the beginning. -This also implies that a stream may not be recognized as readable when data -is still left in PHP's internal stream buffers. -As such, it's recommended to use `stream_set_read_buffer($stream, 0);` -to disable PHP's internal read buffer in this case. -See also [`addReadStream()`](#addreadstream) for more details. - -#### ~~ExtLibevLoop~~ - -> Deprecated since v1.2.0, use [`ExtEvLoop`](#extevloop) instead. - -An `ext-libev` based event loop. - -This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev), -that provides an interface to `libev` library. -`libev` itself supports a number of system-specific backends (epoll, kqueue). - -This loop does only work with PHP 5. -An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8) -to happen any time soon. - ### LoopInterface #### run() diff --git a/src/ExtLibevLoop.php b/src/ExtLibevLoop.php deleted file mode 100644 index c303fdd5..00000000 --- a/src/ExtLibevLoop.php +++ /dev/null @@ -1,201 +0,0 @@ -loop = new EventLoop(); - $this->futureTickQueue = new FutureTickQueue(); - $this->timerEvents = new SplObjectStorage(); - $this->signals = new SignalsHandler(); - } - - public function addReadStream($stream, $listener) - { - if (isset($this->readEvents[(int) $stream])) { - return; - } - - $callback = function () use ($stream, $listener) { - \call_user_func($listener, $stream); - }; - - $event = new IOEvent($callback, $stream, IOEvent::READ); - $this->loop->add($event); - - $this->readEvents[(int) $stream] = $event; - } - - public function addWriteStream($stream, $listener) - { - if (isset($this->writeEvents[(int) $stream])) { - return; - } - - $callback = function () use ($stream, $listener) { - \call_user_func($listener, $stream); - }; - - $event = new IOEvent($callback, $stream, IOEvent::WRITE); - $this->loop->add($event); - - $this->writeEvents[(int) $stream] = $event; - } - - public function removeReadStream($stream) - { - $key = (int) $stream; - - if (isset($this->readEvents[$key])) { - $this->readEvents[$key]->stop(); - $this->loop->remove($this->readEvents[$key]); - unset($this->readEvents[$key]); - } - } - - public function removeWriteStream($stream) - { - $key = (int) $stream; - - if (isset($this->writeEvents[$key])) { - $this->writeEvents[$key]->stop(); - $this->loop->remove($this->writeEvents[$key]); - unset($this->writeEvents[$key]); - } - } - - public function addTimer($interval, $callback) - { - $timer = new Timer( $interval, $callback, false); - - $that = $this; - $timers = $this->timerEvents; - $callback = function () use ($timer, $timers, $that) { - \call_user_func($timer->getCallback(), $timer); - - if ($timers->contains($timer)) { - $that->cancelTimer($timer); - } - }; - - $event = new TimerEvent($callback, $timer->getInterval()); - $this->timerEvents->attach($timer, $event); - $this->loop->add($event); - - return $timer; - } - - public function addPeriodicTimer($interval, $callback) - { - $timer = new Timer($interval, $callback, true); - - $callback = function () use ($timer) { - \call_user_func($timer->getCallback(), $timer); - }; - - $event = new TimerEvent($callback, $timer->getInterval(), $timer->getInterval()); - $this->timerEvents->attach($timer, $event); - $this->loop->add($event); - - return $timer; - } - - public function cancelTimer(TimerInterface $timer) - { - if (isset($this->timerEvents[$timer])) { - $this->loop->remove($this->timerEvents[$timer]); - $this->timerEvents->detach($timer); - } - } - - public function futureTick($listener) - { - $this->futureTickQueue->add($listener); - } - - public function addSignal($signal, $listener) - { - $this->signals->add($signal, $listener); - - if (!isset($this->signalEvents[$signal])) { - $signals = $this->signals; - $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) { - $signals->call($signal); - }, $signal); - $this->loop->add($this->signalEvents[$signal]); - } - } - - public function removeSignal($signal, $listener) - { - $this->signals->remove($signal, $listener); - - if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) { - $this->signalEvents[$signal]->stop(); - $this->loop->remove($this->signalEvents[$signal]); - unset($this->signalEvents[$signal]); - } - } - - public function run() - { - $this->running = true; - - while ($this->running) { - $this->futureTickQueue->tick(); - - $flags = EventLoop::RUN_ONCE; - if (!$this->running || !$this->futureTickQueue->isEmpty()) { - $flags |= EventLoop::RUN_NOWAIT; - } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) { - break; - } - - $this->loop->run($flags); - } - } - - public function stop() - { - $this->running = false; - } -} diff --git a/src/ExtLibeventLoop.php b/src/ExtLibeventLoop.php deleted file mode 100644 index 099293a4..00000000 --- a/src/ExtLibeventLoop.php +++ /dev/null @@ -1,285 +0,0 @@ -eventBase = \event_base_new(); - $this->futureTickQueue = new FutureTickQueue(); - $this->timerEvents = new SplObjectStorage(); - $this->signals = new SignalsHandler(); - - $this->createTimerCallback(); - $this->createStreamCallback(); - } - - public function addReadStream($stream, $listener) - { - $key = (int) $stream; - if (isset($this->readListeners[$key])) { - return; - } - - $event = \event_new(); - \event_set($event, $stream, \EV_PERSIST | \EV_READ, $this->streamCallback); - \event_base_set($event, $this->eventBase); - \event_add($event); - - $this->readEvents[$key] = $event; - $this->readListeners[$key] = $listener; - } - - public function addWriteStream($stream, $listener) - { - $key = (int) $stream; - if (isset($this->writeListeners[$key])) { - return; - } - - $event = \event_new(); - \event_set($event, $stream, \EV_PERSIST | \EV_WRITE, $this->streamCallback); - \event_base_set($event, $this->eventBase); - \event_add($event); - - $this->writeEvents[$key] = $event; - $this->writeListeners[$key] = $listener; - } - - public function removeReadStream($stream) - { - $key = (int) $stream; - - if (isset($this->readListeners[$key])) { - $event = $this->readEvents[$key]; - \event_del($event); - \event_free($event); - - unset( - $this->readEvents[$key], - $this->readListeners[$key] - ); - } - } - - public function removeWriteStream($stream) - { - $key = (int) $stream; - - if (isset($this->writeListeners[$key])) { - $event = $this->writeEvents[$key]; - \event_del($event); - \event_free($event); - - unset( - $this->writeEvents[$key], - $this->writeListeners[$key] - ); - } - } - - public function addTimer($interval, $callback) - { - $timer = new Timer($interval, $callback, false); - - $this->scheduleTimer($timer); - - return $timer; - } - - public function addPeriodicTimer($interval, $callback) - { - $timer = new Timer($interval, $callback, true); - - $this->scheduleTimer($timer); - - return $timer; - } - - public function cancelTimer(TimerInterface $timer) - { - if ($this->timerEvents->contains($timer)) { - $event = $this->timerEvents[$timer]; - \event_del($event); - \event_free($event); - - $this->timerEvents->detach($timer); - } - } - - public function futureTick($listener) - { - $this->futureTickQueue->add($listener); - } - - public function addSignal($signal, $listener) - { - $this->signals->add($signal, $listener); - - if (!isset($this->signalEvents[$signal])) { - $this->signalEvents[$signal] = \event_new(); - \event_set($this->signalEvents[$signal], $signal, \EV_PERSIST | \EV_SIGNAL, array($this->signals, 'call')); - \event_base_set($this->signalEvents[$signal], $this->eventBase); - \event_add($this->signalEvents[$signal]); - } - } - - public function removeSignal($signal, $listener) - { - $this->signals->remove($signal, $listener); - - if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) { - \event_del($this->signalEvents[$signal]); - \event_free($this->signalEvents[$signal]); - unset($this->signalEvents[$signal]); - } - } - - public function run() - { - $this->running = true; - - while ($this->running) { - $this->futureTickQueue->tick(); - - $flags = \EVLOOP_ONCE; - if (!$this->running || !$this->futureTickQueue->isEmpty()) { - $flags |= \EVLOOP_NONBLOCK; - } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) { - break; - } - - \event_base_loop($this->eventBase, $flags); - } - } - - public function stop() - { - $this->running = false; - } - - /** - * Schedule a timer for execution. - * - * @param TimerInterface $timer - */ - private function scheduleTimer(TimerInterface $timer) - { - $this->timerEvents[$timer] = $event = \event_timer_new(); - - \event_timer_set($event, $this->timerCallback, $timer); - \event_base_set($event, $this->eventBase); - \event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND); - } - - /** - * Create a callback used as the target of timer events. - * - * A reference is kept to the callback for the lifetime of the loop - * to prevent "Cannot destroy active lambda function" fatal error from - * the event extension. - */ - private function createTimerCallback() - { - $that = $this; - $timers = $this->timerEvents; - $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) { - \call_user_func($timer->getCallback(), $timer); - - // Timer already cancelled ... - if (!$timers->contains($timer)) { - return; - } - - // Reschedule periodic timers ... - if ($timer->isPeriodic()) { - \event_add( - $timers[$timer], - $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND - ); - - // Clean-up one shot timers ... - } else { - $that->cancelTimer($timer); - } - }; - } - - /** - * Create a callback used as the target of stream events. - * - * A reference is kept to the callback for the lifetime of the loop - * to prevent "Cannot destroy active lambda function" fatal error from - * the event extension. - */ - private function createStreamCallback() - { - $read =& $this->readListeners; - $write =& $this->writeListeners; - $this->streamCallback = function ($stream, $flags) use (&$read, &$write) { - $key = (int) $stream; - - if (\EV_READ === (\EV_READ & $flags) && isset($read[$key])) { - \call_user_func($read[$key], $stream); - } - - if (\EV_WRITE === (\EV_WRITE & $flags) && isset($write[$key])) { - \call_user_func($write[$key], $stream); - } - }; - } -} diff --git a/src/Factory.php b/src/Factory.php index 30bbfd7c..3d71ab97 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -52,10 +52,6 @@ private static function construct() return new ExtUvLoop(); } - if (\class_exists('libev\EventLoop', false)) { - return new ExtLibevLoop(); - } - if (\class_exists('EvLoop', false)) { return new ExtEvLoop(); } @@ -64,11 +60,6 @@ private static function construct() return new ExtEventLoop(); } - if (\function_exists('event_base_new') && \PHP_MAJOR_VERSION === 5) { - // only use ext-libevent on PHP 5 for now - return new ExtLibeventLoop(); - } - return new StreamSelectLoop(); // @codeCoverageIgnoreEnd } diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index 1686fd74..943a81aa 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -15,9 +15,8 @@ * This event loop works out of the box on PHP 5.4 through PHP 8+ and HHVM. * This means that no installation is required and this library works on all * platforms and supported PHP versions. - * Accordingly, the [`Loop` class](#loop) and the deprecated [`Factory`](#factory) - * will use this event loop by default if you do not install any of the event loop - * extensions listed below. + * Accordingly, the [`Loop` class](#loop) will use this event loop by default if + * you do not install any of the event loop extensions listed below. * * Under the hood, it does a simple `select` system call. * This system call is limited to the maximum file descriptor number of diff --git a/tests/ExtLibevLoopTest.php b/tests/ExtLibevLoopTest.php deleted file mode 100644 index 19a5e876..00000000 --- a/tests/ExtLibevLoopTest.php +++ /dev/null @@ -1,22 +0,0 @@ -markTestSkipped('libev tests skipped because ext-libev is not installed.'); - } - - return new ExtLibevLoop(); - } - - public function testLibEvConstructor() - { - $loop = new ExtLibevLoop(); - } -} diff --git a/tests/ExtLibeventLoopTest.php b/tests/ExtLibeventLoopTest.php deleted file mode 100644 index 524e0548..00000000 --- a/tests/ExtLibeventLoopTest.php +++ /dev/null @@ -1,63 +0,0 @@ -markTestSkipped('libevent tests skipped on linux due to linux epoll issues.'); - } - - if (!function_exists('event_base_new')) { - $this->markTestSkipped('libevent tests skipped because ext-libevent is not installed.'); - } - - return new ExtLibeventLoop(); - } - - /** - * @after - */ - public function tearDownFile() - { - if ($this->fifoPath !== null && file_exists($this->fifoPath)) { - unlink($this->fifoPath); - } - } - - public function createStream() - { - if ('Linux' !== PHP_OS) { - return parent::createStream(); - } - - $this->fifoPath = tempnam(sys_get_temp_dir(), 'react-'); - assert(is_string($this->fifoPath)); - - unlink($this->fifoPath); - - // Use a FIFO on linux to get around lack of support for disk-based file - // descriptors when using the EPOLL back-end. - posix_mkfifo($this->fifoPath, 0600); - - $stream = fopen($this->fifoPath, 'r+'); - - return $stream; - } - - public function writeToStream($stream, $content) - { - if ('Linux' !== PHP_OS) { - return parent::writeToStream($stream, $content); - } - - fwrite($stream, $content); - } -} diff --git a/tests/Timer/ExtLibevTimerTest.php b/tests/Timer/ExtLibevTimerTest.php deleted file mode 100644 index 65e82bee..00000000 --- a/tests/Timer/ExtLibevTimerTest.php +++ /dev/null @@ -1,17 +0,0 @@ -markTestSkipped('libev tests skipped because ext-libev is not installed.'); - } - - return new ExtLibevLoop(); - } -} diff --git a/tests/Timer/ExtLibeventTimerTest.php b/tests/Timer/ExtLibeventTimerTest.php deleted file mode 100644 index 9089b9a5..00000000 --- a/tests/Timer/ExtLibeventTimerTest.php +++ /dev/null @@ -1,17 +0,0 @@ -markTestSkipped('libevent tests skipped because ext-libevent is not installed.'); - } - - return new ExtLibeventLoop(); - } -}