Skip to content

fix(ext/napi): add uv_cond_* polyfills for native addons#35536

Merged
bartlomieju merged 3 commits into
denoland:mainfrom
minato32:fix/34736-uv-cond
Jul 2, 2026
Merged

fix(ext/napi): add uv_cond_* polyfills for native addons#35536
bartlomieju merged 3 commits into
denoland:mainfrom
minato32:fix/34736-uv-cond

Conversation

@minato32

Copy link
Copy Markdown
Contributor

Closes #34736.

Native addons that link against libuv directly (e.g. @sap/hana-client) use libuv's condition variables. The host binary only exported uv_mutex_*, uv_sem_* and uv_thread_*, so loading such an addon failed:

undefined symbol: uv_cond_init

This adds the missing condition-variable symbols: uv_cond_init, uv_cond_destroy, uv_cond_signal, uv_cond_broadcast, uv_cond_wait, uv_cond_timedwait.

They follow the existing uv_sem_* / uv_thread_* approach in ext/napi/uv.rs: the opaque, platform-specific uv_cond_t the addon allocates only stores a small token, and the real state lives in a process-global registry, so we don't depend on its layout (a u32 fits the smallest uv_cond_t, Windows' pointer-sized CONDITION_VARIABLE).

The condvar is backed by its own internal mutex rather than the addon's uv_mutex_t. uv_cond_wait takes the internal mutex, releases the addon mutex, then blocks on the internal mutex; a concurrent uv_cond_signal/uv_cond_broadcast must take that same internal mutex to notify and can't acquire it until the waiter is parked, so no wakeup is lost. uv_cond_timedwait returns UV_ETIMEDOUT (-4039) on timeout.

The new symbols are added to symbol_exports.json and the regenerated .def lists so they land in the binary's dynamic symbol table.

Tests

  • Rust unit test in ext/napi/uv.rs driving uv_cond_* with a worker thread + uv_mutex, plus a size-fits assertion for the token.
  • End-to-end NAPI addon test (tests/napi/src/uv.rs + uv_test.js): a real .node addon resolves the symbols from the host deno at runtime and a worker signals a condition variable the main thread waits on. Verified passing locally.

minato32 and others added 3 commits June 26, 2026 14:59
Native addons that link against libuv directly (e.g. `@sap/hana-client`) use
libuv's condition variables, but the host binary only exported `uv_mutex_*`,
`uv_sem_*` and `uv_thread_*`. Loading such an addon failed with
`undefined symbol: uv_cond_init`.

Add `uv_cond_init`, `uv_cond_destroy`, `uv_cond_signal`, `uv_cond_broadcast`,
`uv_cond_wait` and `uv_cond_timedwait`, following the existing semaphore/thread
approach: the opaque, platform-specific `uv_cond_t` allocated by the addon
stores a small token while the real state lives in a process-global registry.
The condvar is backed by its own internal mutex (not the addon's `uv_mutex_t`)
that is held across the addon-mutex release, so a concurrent signal can't be
lost. The new symbols are added to `symbol_exports.json` and the generated
`.def` lists so they end up in the binary's dynamic symbol table.

Closes denoland#34736
…to e2e

uv_cond_timedwait hardcoded -4039 for the timeout case, but that is only
libuv's fallback for Windows (and platforms without ETIMEDOUT). On unix
UV_ETIMEDOUT is -ETIMEDOUT (-110 on Linux, -60 on macOS), so an addon
comparing the return against its own UV_ETIMEDOUT never matched and misread
a timeout. Derive the value per platform from libc, mirroring libuv's
uv/errno.h.

Drop the in-process unit test for the cond polyfills in favor of the
end-to-end napi addon test, which resolves the symbols from the host deno
binary at runtime (the thing this change actually ships). The e2e test now
asserts the exact platform UV_ETIMEDOUT rather than just a non-zero code, so
it would catch the value regression. The cheap size-fits assertion stays in
the unit sizes() test.
…ters

The existing uv_cond e2e test only exercised uv_cond_signal with a single
waiter and the timedwait timeout. uv_cond_broadcast and the multiple-waiter
path had no coverage. Add test_uv_cond_broadcast: several worker threads park
in uv_cond_wait on the same condition variable, and once all are parked the
main thread wakes every one of them with a single uv_cond_broadcast, asserting
all workers ran.

@bartlomieju bartlomieju left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@bartlomieju
bartlomieju merged commit 5766ec5 into denoland:main Jul 2, 2026
136 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@sap/hana-client native addon fails to load: undefined symbol uv_cond_init

2 participants