Skip to content

symplely/ext-uv

 
 

Repository files navigation

ext-uv

Apple macOS CentOS 7 CentOS stream Ubuntu Windows PHP 7.4 Windows PHP 8+

Interface to libuv for php.

Compiling for Linux, macOS, and Windows

For Apple macOS

brew install libuv autoconf automake libtool pkg-config

For Debian like distributions, Ubuntu...

apt-get install libuv1-dev php-pear -y

The quickest way to get ZTS PHP versions for ubuntu is by way of shivammathur/php-builder. This method installs all extensions, to disable do: sudo phpdismod xdebug.

curl -sSLO https://github.com/shivammathur/php-builder/releases/latest/download/install.sh
chmod a+x ./install.sh
# ./install.sh <php-version> <release|debug> <nts|zts>
./install.sh 8.2 debug zts

For RedHat like distributions, CentOS...

yum install libuv-devel php-pear -y

To build libuv .so library from source

git clone https://github.com/libuv/libuv.git
cd libuv
cmake . -DBUILD_TESTING=ON
cmake --build . --config Release
ls -lh
cp include/uv/* deps/include/uv
cp include/* deps/include/
cp Release/uv.la deps/lib
cp Release/uv.so deps/lib

To build ext-uv .so

# any branch except `master`, will contain more unfinished broken buggy development work
git clone --branch 0.3x https://github.com/symplely/ext-uv.git
cd ext-uv
phpize
./configure --with-uv=$(readlink -f `pwd`/libuv)
make
make install
echo "extension=uv.so" >> "$(php -r 'echo php_ini_loaded_file();')"

For Windows - needs Visual Studio 2019

git clone https://github.com/symplely/ext-uv.git
cd ext-uv
rem passing `--shared` results in uv.dll, php_uv.dll modules not loading correctly
.\cmd\compile_x64.bat --php 8.2.4 --ts
rem for testing
.\cmd\windows_run_test.bat --php 8.2.4 --ts
rem files in
dir php-sdk\phpdev\vs16\x64\php-8.2.4\x64\

Binaries for PHP 7.4 - 8.2

  • See Releases page, for Windows, Linux - Debian/Redhat, Apple macOS - 10.15, 11, 12
  • PHP 8+ versions for Windows are static builds, issues building --shared, results in a shared module not loading correctly. PHP 7.4 for Windows can be built static or shared and correctly loads.

Or bypass both and just use libuv FFI version symplely/uv-ffi

Examples

<?php
$tcp = uv_tcp_init();

uv_tcp_bind($tcp, uv_ip4_addr('0.0.0.0',8888));

uv_listen($tcp,100, function($server){
    $client = uv_tcp_init();
    uv_accept($server, $client);
    var_dump(uv_tcp_getsockname($server));

    uv_read_start($client, function($socket, $nread, $buffer){
        var_dump($buffer);
        uv_close($socket);
    });
});

$c = uv_tcp_init();
uv_tcp_connect($c, uv_ip4_addr('0.0.0.0',8888), function($stream, $stat){
    if ($stat == 0) {
        uv_write($stream,"Hello",function($stream, $stat){
            uv_close($stream);
        });
    }
});

uv_run();

Original Author

  • Shuhei Tanuma

License

PHP License

Documentation

Use your favorite IDE and pull in the provided stubs, most functions DocBlock give overview of usage.

For deeper usage understanding, see the online book or An Introduction to libuv for a full tutorial overview.

Basic overview of libuv

Design

libuv is cross-platform support library which was originally written for Node.js. It’s designed around the event-driven asynchronous I/O model.

The library provides much more than a simple abstraction over different I/O polling mechanisms: ‘handles’ and ‘streams’ provide a high level abstraction for sockets and other entities; cross-platform file I/O and threading functionality is also provided, amongst other things.

Handles and Requests

libuv provides users with 2 abstractions to work with, in combination with the event loop: handles and requests.

Handles represent long-lived objects capable of performing certain operations while active. Some examples:

  • A prepare handle gets its callback called once every loop iteration when active.
  • A TCP server handle that gets its connection callback called every time there is a new connection.

Requests represent (typically) short-lived operations. These operations can be performed over a handle: uv_write requests are used to write data on a handle; or standalone: uv_getaddrinfo requests don’t need a handle they run directly on the loop.

The I/O loop

The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O operations, and it’s meant to be tied to a single thread. One can run multiple event loops as long as each runs in a different thread. The libuv event loop (or any other API involving the loop or handles, for that matter) is not thread-safe except where stated otherwise.

The event loop follows the rather usual single threaded asynchronous I/O approach:

  • all (network) I/O is performed on non-blocking sockets which are polled using the best mechanism available on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP on Windows.

  • As part of a loop iteration the loop will block waiting for I/O activity on sockets which have been added to the poller and callbacks will be fired indicating socket conditions (readable, writable hangup) so handles can read, write or perform the desired I/O operation.

  • Use a thread pool to make asynchronous file I/O operations possible, but network I/O is always performed in a single thread, each loop’s thread.

Note: While the polling mechanism is different, libuv makes the execution model consistent across Unix systems and Windows.

loop

File I/O

Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, so the current approach is to run blocking file I/O operations in a thread pool.

For a thorough explanation of the cross-platform file I/O landscape, checkout this post.

libuv currently uses a global thread pool on which all loops can queue work. 3 types of operations are currently run on this pool:

  • File system operations
  • DNS functions (uv_getaddrinfo)
  • User specified code via uv_queue_work()

Thread pool work scheduling

libuv provides a threadpool which can be used to run user code and get notified in the loop thread. This thread pool is internally used to run all file system operations, as well as uv_getaddrinfo requests.

Its default size is 4, but it can be changed at startup time (the absolute maximum is 1024).

The threadpool is global and shared across all event loops. When a particular function makes use of the threadpool (i.e. when using uv_queue_work()) libuv preallocates and initializes the maximum number of threads allowed. This causes a relatively minor memory overhead (~1MB for 128 threads) but increases the performance of threading at runtime.

Note that even though a global thread pool which is shared across all events loops is used, the functions are not thread safe.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C 58.6%
  • PHP 37.5%
  • Batchfile 2.6%
  • M4 0.9%
  • Shell 0.2%
  • JavaScript 0.2%