Skip to content

libuv-wasix: posix_spawn child processes on WASIX#7

Merged
Arshia001 merged 5 commits into
wasix-1.51.0from
fix/spawn-posix-v2
Jun 23, 2026
Merged

libuv-wasix: posix_spawn child processes on WASIX#7
Arshia001 merged 5 commits into
wasix-1.51.0from
fix/spawn-posix-v2

Conversation

@Arshia001

@Arshia001 Arshia001 commented Jun 23, 2026

Copy link
Copy Markdown

Summary

Replace broken WASIX child-process behavior with a posix_spawnp() backend for wasm EH builds, while preserving real fork() on WASIX without exception handling.

  • Dispatch posix_spawnp from uv__spawn_resolve_and_spawn on __wasi__
  • Reap children via libc waitpid(WNOHANG) (no direct __wasi_* imports in libuv)
  • Poll uv__wait_children() after uv__io_poll(); only cap unbounded poll sleep (timeout < 0) to UV__WASIX_CHILD_POLL_MS at the poll call site
  • Return UV_ENOSYS from the fork fallback only when __wasi__ && __wasm_exception_handling__ (EH/asyncify-incompatible); restore normal fork otherwise
  • Use uv_pipe() for unidirectional child stdio where socketpair(AF_UNIX) is unreliable on WASIX
  • Includes WASIX UDP multicast/disconnect shims from prior work

Rebased onto wasix-1.51.0 (supersedes #1, closed as duplicate).

Test plan

EdgeJS WASIX (EH build, scripts/edge-wasix-node-runner.sh, libuv ff7c7ca8):

  • spawnSync(process.execPath, ['-e', ...]) (~330–380ms each)
  • multiline -e argv preservation
  • cross-spawn.sync(process.execPath, ...)
  • invalid binary path fails fast
  • non-EH WASIX build: fork/cluster path (not yet verified)

@Arshia001

Copy link
Copy Markdown
Author

Supersedes #1 (now closed as duplicate).

Branch fix/spawn-posix-v2 is based on ea792e2 + UDP shim 14630b9, spawn commit d8ebea9.

EdgeJS verification (via scripts/edge-wasix-node-runner.sh, submodule d8ebea9):

  • spawnSync(process.execPath, ['-e', ...]) — ~350ms, no hang
  • multiline -e argv preservation
  • cross-spawn.sync(process.execPath, ...) — no hang
  • invalid binary path fails fast (no hang)
  • async spawn(..., { stdio: 'inherit' }) — exit 0

@Arshia001

Copy link
Copy Markdown
Author

Update: restored the real `uv__spawn_and_init_child_fork()` implementation from before ea792e2. Fork is only disabled when both `wasi` and `wasm_exception_handling` are defined (wasixcc exnref/EH builds). Non-EH WASIX uses asyncify and can fork normally; EH builds still fall through to the posix_spawn path via `UV_ENOSYS`.

Commit: 1b66832

@Arshia001 Arshia001 force-pushed the fix/spawn-posix-v2 branch from 1b66832 to ff7c7ca Compare June 23, 2026 18:48
@Arshia001 Arshia001 changed the base branch from ubi to wasix-1.51.0 June 23, 2026 18:48
@Arshia001

Copy link
Copy Markdown
Author

Rebased `fix/spawn-posix-v2` onto `wasix-1.51.0` and retargeted this PR.

New tip: `ff7c7ca8` (3 commits on top of libuv 1.51.0 + wasix build scripts). Drops the old `ubi`/`disable fork` history; fork is restored with an EH-only `UV_ENOSYS` stub (`wasm_exception_handling`).

marxin and others added 5 commits June 23, 2026 19:23
…ct avoids the unsupported AF_UNSPEC connect() trick. WASIX connected-state checks now trust libuv’s handle flag.
Replace the fake fork success stub with a WASIX posix_spawnp backend and
reap children through libc waitpid(WNOHANG) instead of direct __wasi_* calls.

- Dispatch posix_spawnp from uv__spawn_resolve_and_spawn on __wasi__
- Return UV_ENOSYS from the fork fallback so failed spawns fail fast
- Poll uv__wait_children after uv__io_poll and cap backend timeout when
  process handles are pending (no reliable SIGCHLD on WASIX)
- Use uv_pipe for unidirectional child stdio where socketpair is unreliable

Co-authored-by: Cursor <cursoragent@cursor.com>
Move child-exit polling out of uv__backend_timeout so uv_backend_timeout()
and timer-driven poll deadlines stay accurate. When a spawned child is still
tracked and the loop would poll forever, cap that single poll to
UV__WASIX_CHILD_POLL_MS before calling uv__io_poll().

Co-authored-by: Cursor <cursoragent@cursor.com>
@Arshia001

Copy link
Copy Markdown
Author

Fix: restored the two `ubi` commits that sit between `wasix-1.51.0` and `disable fork`:

  • `876682c4` Do not use some missing wasix IPV6 related functions (`tcp.c`, `uv-common.c`)
  • `767df34a` disable one function from the API (`uv.h`, `getaddrinfo.c`)

These were dropped when rebasing directly onto `wasix-1.51.0`. The branch now has 5 commits on top of `wasix-1.51.0` (tip `4923dd2d`), still without `ea792e22 disable fork`.

```
4923dd2 wasix: clamp only unbounded poll sleep for live children
eb7fa2e libuv-wasix: posix_spawn child processes on WASIX
c2f84cd WASIX UDP multicast/disconnect shims
b1286f4 disable one function from the API
1336fe8 Do not use some missing wasix IPV6 related functions
```

@Arshia001 Arshia001 force-pushed the fix/spawn-posix-v2 branch from ff7c7ca to 4923dd2 Compare June 23, 2026 19:23
@Arshia001 Arshia001 merged commit cb7e09a into wasix-1.51.0 Jun 23, 2026
@Arshia001 Arshia001 deleted the fix/spawn-posix-v2 branch June 23, 2026 19:27
Arshia001 added a commit to wasmerio/edgejs that referenced this pull request Jun 24, 2026
Track cb7e09ae on wasix-1.51.0 so WASIX child_process uses the squashed
spawn, waitpid polling, and EH-gated fork fallback from wasix-org/libuv#7.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

4 participants