deno
bc58c2af - fix(core): deactivate idle TTY write handles (#35886)

Commit
23 days ago
fix(core): deactivate idle TTY write handles (#35886) ## Summary Allow Node-compatible TTY stdio writes to drain and then stop keeping Deno alive, without changing the observable ref state of the underlying stdio handle where that handle is exposed. Adds a PTY integration regression for a large `process.stderr.write()` that verifies the write callback runs and the process exits. On platforms that expose `process.stderr._handle.hasRef()`, it also verifies the handle remains ref'ed before and inside the callback. ## Root Cause `uv_tty_init()` creates TTY handles with `UV_HANDLE_REF`, matching Node's observable `process.stderr._handle.hasRef() === true` behavior for stdio TTYs where `_handle` is exposed. Deno's `uv_compat` write path also marks TTY handles `UV_HANDLE_ACTIVE` via `ensure_tty_registered()`. Plain TTY writes drained their callbacks, but the normal write-drain path did not clear `UV_HANDLE_ACTIVE`; only the shutdown path deactivated the handle. Since loop liveness checks count handles that are both active and ref'ed, an idle stdio TTY write handle could keep Deno alive forever after all JS and children had finished. The fix deactivates TTY handles once there is no pending read, write, or shutdown work. It leaves `UV_HANDLE_REF` untouched, so `_handle.hasRef()` remains Node-compatible while idle inactive handles no longer keep the loop alive. Redirected output avoids the TTY stream path, which is why the same script exited with stdout/stderr redirected. ## Validation - `./tools/format.js ext/node/polyfills/process.ts libs/core/uv_compat/tty.rs tests/integration/run_tests.rs tests/testdata/run/process_stderr_tty_write_exit.js` - `cargo test --test integration process_stderr_tty_write_exit` - `cargo test -p deno_core uv_compat` - `./tools/lint.js` - Manual PTY reduction: large `process.stderr.write()` exits and reports `_handle.hasRef()` as `true` before and inside the callback on macOS - Manual PTY validation in `../v8x`: `target/debug/deno run -A tests/harness/run.mjs rusty_v8 quickjs --rescue` exits cleanly with `pass=267 fail=0 skip=0` - CI: `test integration (1/2) debug windows-x86_64` passed on head `3a9f366bf34b16ad3b0c12117233460c5320e2a0`
Author
Parents
Loading