Fix guest TCP recv() stalling when v86 NE2000 TX ring wraps (#363)

* Fix guest TCP recv() stalling under concurrent traffic

v86's fake_network stores TCPConnection routing fields (hsrc/hdest/
psrc/pdest) as zero-copy subarrays of the SYN frame, which is itself a
view into the NE2000 TX ring. Win95's driver uses a 12-slot ring; once
it wraps (any concurrent SMB/NBNS/ping while waiting for an upstream
reply), pump() emits segments with whatever IP now occupies that slot,
the guest RSTs them, and recv() blocks forever.

- libv86.js: copy the four address arrays at TCPConnection construction
  (matches felixrieseberg/v86@dd13099c on fake-network-copy-tcp-addrs,
  now merged into windows95-base)
- tools/probe-tcp.sh + net/tcp-trace.ts + tcp-relay.ts test stub +
  debug-harness WIN95_PROBE_RUN2: end-to-end regression harness
  (boot → ping -t → telnet → async write after ring wrap → assert ACK).
  All env-gated, no production-path change.
- docs/v86-patches.md: tracker for all fork patches + upstream PR state
- update-v86 SKILL.md: cross-link and new fork-branch entry

* Drop checked-in upstream PR description

Belongs on the GitHub PR, not in the repo.
This commit is contained in:
Felix Rieseberg
2026-04-12 08:03:03 -07:00
committed by GitHub
parent 3c63139fae
commit b74e6c7b0a
8 changed files with 273 additions and 2 deletions

View File

@@ -23,7 +23,9 @@ fallbacks, no fetching from copy.sh.
## The fork branch
v86 should be checked out on **`felixrieseberg/v86:windows95-base`**.
That branch merges four feature branches, each upstreamable on its own:
That branch merges the feature branches tracked in
[`docs/v86-patches.md`](../../../docs/v86-patches.md) — keep that table
in sync with this list. Each is upstreamable on its own:
- **`electron-renderer-fs-loader`** (PR #1540) — `src/lib.js` uses
`require("fs")` instead of `await import("node:fs/promises")`. Dynamic
@@ -42,6 +44,14 @@ That branch merges four feature branches, each upstreamable on its own:
69 so `W95TOOLS.EXE` (guest-tools/agent) can sync `CF_TEXT` with
the host. Consumes `mouse-absolute` and `vmware-clipboard-host` bus
events; emits `vmware-absolute-mouse` and `vmware-clipboard-guest`.
- **`fake-network-copy-tcp-addrs`** — `src/browser/fake_network.js`
copies the four address subarrays (`hsrc/hdest/psrc/pdest`) when a
`TCPConnection` is created from an inbound SYN. Upstream stores them
as zero-copy views into the NE2000 TX ring; once the guest's 12-slot
TX ring wraps (any concurrent traffic — SMB, NBNS, ping), `pump()`
builds segments with whatever IP now occupies that slot, the guest
RSTs them as belonging to no TCB, and `recv()` blocks forever.
Exercised by `tools/probe-tcp.sh`.
- **`vga-defer-vbe-disable-v86`** — `src/vga.js` defers `dispi[4]=0`
written from V86 mode until a legacy attribute-mode write reaches the
hardware. Win9x's VDD virtualises ports 3B03DF for a windowed DOS VM