deno
17e4d5ed - fix(ext/napi): polyfill libuv thread + semaphore primitives (#34571)

Commit
54 days ago
fix(ext/napi): polyfill libuv thread + semaphore primitives (#34571) ## Summary Follow-up to #34488, which added the first tier of libuv polyfills so native addons that link against libuv directly (e.g. `@sentry/profiling-node`) can resolve their `uv_*` undefined symbols at `dlopen` time. That PR's review asked to verify which of the open [`node native extension`](https://github.com/denoland/deno/issues?q=state%3Aopen%20label%3A%22node%20native%20extension%22) issues it fixed or moved forward. The most common *remaining* failure mode for that class of addon is libuv's portable **threading and synchronization** primitives (`uv_thread_*`, `uv_sem_*`) — addons use them for their own background work instead of the raw OS APIs, and on macOS a missing one surfaces as the infamous `dyld: missing symbol called`. This PR adds those primitives to the compat layer: - `uv_thread_create` / `uv_thread_join` / `uv_thread_self` / `uv_thread_equal` — backed by `std::thread`. We hand out a `u64` token (stored in the addon-allocated `uv_thread_t`, which is always pointer-sized) and keep the real `JoinHandle` in a process-global registry, so `uv_thread_self` / `uv_thread_equal` stay consistent and we never depend on the platform `pthread_t` / `HANDLE` layout. - `uv_sem_init` / `uv_sem_destroy` / `uv_sem_post` / `uv_sem_wait` / `uv_sem_trywait` — a counting semaphore built on `parking_lot`. `uv_sem_t` is as small as a 4-byte mach `semaphore_t` on macOS (vs a 32-byte `sem_t` on Linux), so we store only a `u32` token in the addon struct and keep the state in a registry too. The registry lock is held only to look the semaphore up, never while blocking in `uv_sem_wait`. These primitives are self-contained — they never touch the event loop — so the polyfills are exact, unlike the loop-bound handles which have to be bridged onto `deno_core`'s `uv_compat` layer. ### Verification of the `node native extension` issues vs #34488 | Issue | Failure | Status after #34488 | | --- | --- | --- | | #28621 zeromq v6 | `undefined symbol: uv_unref` | **Fixed** — #34488 added `uv_unref` | | #26421 @sentry/profiling-node | `dyld missing symbol called` | **Partial** — libuv half fixed; V8 C++ ABI half still blocked (out of scope, needs a `rusty_v8` change) | | #26656 node-rdkafka, #29152 node-pty | `dyld missing symbol called` | **Class addressed here** — these reach for libuv threading primitives this PR adds | | #18345 zeromq v5 | `napi_register_module_v1 not found` | Unrelated (NAN/node-gyp addon registration) | | #16578 sharp, #24395 oracledb | module resolution / wrong arch `.node` | Unrelated to uv symbols | | #23465, #17411, #16642, #25956 | `LoadLibraryExW failed` (Windows DLL deps) | Unrelated to uv symbols | | #29203 @duckdb/node-api | `deno compile` `@rpath/libduckdb.dylib` not found | Unrelated to uv symbols | ## Test plan - [x] `cargo check -p deno_napi -p test_napi` - [x] `cargo clippy -p deno_napi -p test_napi --all-targets` - [x] `cargo test -p deno_napi` — new `uv::tests::thread_and_semaphore` unit test passes (a worker thread posts a counting semaphore three times; the main thread drains it, joins the worker, and checks `uv_sem_trywait` / `uv_thread_equal`), alongside the existing `sizes` test. - [x] New `napi uv thread + semaphore` integration test (`tests/napi`) — a worker thread increments a counter and posts a counting semaphore three times; the main thread drains the semaphore, joins the worker, and asserts the results. Exercises every new symbol, resolved from the host `deno` binary at runtime. - [x] Existing `ext/napi` uv tests still pass. - [ ] CI Refs #34488 Closes denoland/orchid#333 --------- Co-authored-by: divybot <divybot@users.noreply.github.com> Co-authored-by: Divy Srivastava <me@littledivy.com>
Author
Parents
Loading