Optional libuv poll backend extension for CrossByte.
CrossByte core polls its sockets with its built-in backend (poll(2) on
native builds). This package installs a libuv-backed one through CrossByte's
internal poll backend seam: one uv_poll_t per socket, kept for as long as
the socket is registered, so a wait costs what libuv's epoll, kqueue or IOCP
wait costs rather than a scan of every socket.
Measured on Linux (WSL2, libuv 1.48, bench/PollBench.hx), per call:
| Sockets | Join or leave, built-in | Join or leave, libuv | Wait with 8 ready, built-in | Wait with 8 ready, libuv |
|---|---|---|---|---|
| 1,000 | 114 us | 5.3 us | 81 us | 1.4 us |
| 4,000 | 343 us | 28 us | 380 us | 1.2 us |
| 10,000 | 2,268 us | 44 us | 1,632 us | 1.2 us |
Making the libuv backend's first watchers for a set costs more than the built-in's (32 ms for 10,000 sockets), once.
Install the backend in main, before anything creates a CrossByte runtime:
import crossbyte.libuv.LibuvPoll;
class Main {
public static function main():Void {
if (!LibuvPoll.install()) {
throw "crossbyte-libuv was not compiled with native libuv support";
}
// Create the Application, ServerApplication or runtime after installing.
new MyServer();
}
}A runtime picks its backend when it is made, and again whenever its socket
set grows past its capacity (1,024 by default). So install() and
uninstall() throw IllegalOperationError once a runtime exists: an
Application subclass makes its runtime in its constructor, so calling
install() from there is too late.
To see what a runtime ended up with:
LibuvPoll.isInstalled(); // runtimes made now get libuv
LibuvPoll.isActive(); // this thread's runtime polls through libuv
LibuvPoll.isActive(someRuntime);LibuvPoll compiles on every target, so code shared with JavaScript can call
it; outside a native build with -D crossbyte_libuv_native, install()
returns false and the built-in backend stays.
If libuv cannot start a loop (out of descriptors, say), the backend's factory returns null and the runtime falls back to the built-in backend.
Native builds need three things resolvable by haxelib name, because the
native code is included through ${haxelib:...} paths:
- the hxcpp fork CrossByte is developed against (stock hxcpp does not build current CrossByte);
crossbyte, whose externs include their ownBuild.xml;crossbyte-libuvitself.
haxelib git hxcpp https://github.com/dimensionscape/hxcpp.git production
haxelib dev crossbyte path/to/crossbyte
haxelib dev crossbyte-libuv path/to/crossbyte-libuvAfter a haxelib git of hxcpp, build its tools once, from the directory
haxelib path hxcpp prints: haxe compile.hxml in tools/run and then in
tools/hxcpp.
Then build with the define:
haxe -lib crossbyte -lib crossbyte-libuv -D crossbyte_libuv_native -main Main --cpp export/appWithout -D crossbyte_libuv_native the package still compiles and
LibuvPoll.install() returns false.
The native build compiles against libuv's headers and links its library.
- Linux:
sudo apt-get install libuv1-dev(or your distribution's equivalent). Links-luv. - macOS:
brew install libuv, then pass its prefix:-D LIBUV_INCLUDE=$(brew --prefix libuv)/include -D LIBUV_LIB=$(brew --prefix libuv)/lib. - Windows (MSVC): build libuv with CMake (or take it from vcpkg) and pass
where it is:
-D LIBUV_INCLUDE=C:/libuv/include -D LIBUV_LIB=C:/libuv/lib. By default the build linksuv.lib, which is the import library ofuv.dll: copyuv.dllnext to your executable (or ontoPATH), or it will not start (exit code0xC0000135, a DLL not found). Add-D LIBUV_STATICto link libuv's static library,libuv.lib, instead and ship no DLL. hxcpp links the static C runtime, so build that library with it too, or the link fails on unresolved__imp_symbols:cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ....
LIBUV_INCLUDE and LIBUV_LIB work on every platform, for a libuv that is
not where the compiler looks by default.
With the haxelibs above set up, utest installed (and hxnodejs for the
JavaScript check), and CrossByte checked out beside this repository
(../crossbyte):
haxe test.hxml # interpreter: the API without native support
haxe native-test.hxml # native tests, into ../crossbyte/export/crossbyte-libuv-native-test
../crossbyte/export/crossbyte-libuv-native-test/LibuvNativeTestMain
haxe js-check.hxml && node export/js-check/node.js # LibuvPoll compiles for Node and the browser
haxe bench.hxml && export/bench/PollBench # needs `ulimit -n` above 10,000CB_ONLY=<class name part> runs some of the native test classes.