BT410 5.3.77: the overrun drain loop is not the trigger either
serialnamedpipe's P_RX_BLOCKED path drains its whole backlog when the guest
hasn't read in time -- directserial's `while (doReceive());`. That looked
like the trigger, since a named pipe's backlog is unbounded where a real
port's is capped by the line rate. Bounded it to one byte (real UART overrun
semantics) and re-ran the conf that had faulted 3/3: FAULT 283s, FAULT 226s,
FAULT 204s. Killed.
The measurement that explains why it was never plausible: overruns during a
run are 1-3 per report period, because vRIO sends about a byte every 1-3ms --
the backlog is shallow and the loop had nothing to teleport. The 494/499
counts all land after the game exits. I read the code and inferred a burst
without measuring the queue depth it operates on.
Default restored to drain-all: it is the validated directserial behaviour the
RIO's rxpollus/rxburst tuning was calibrated against, and changing it on a
dead hypothesis would risk real-cockpit timing for nothing.
VPX_RX_OVERRUN_ONE=1 opts into the bounded form.
The roadmap now carries a fault ledger of every dead hypothesis so none get
re-run. What survives: a deterministic DPMI-host path walking a
{next,handler} chain into a node whose pointer is an unhooked IVT value,
entered under RIO interrupt load. Naming the owning routine needs a trace of
entries to host 0x66CF, clean vs faulting -- a DPMI32VM reversing
sub-project, now decoupled from the reconstruction (vRIO down = 100%
reliable, logged conf = ~70%).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -274,7 +274,47 @@ void CSerialNamedPipe::handleUpperEvent(uint16_t type) {
|
||||
rx_retry = 0;
|
||||
removeEvent(SERIAL_RX_EVENT);
|
||||
if (doReceive()) {
|
||||
while (doReceive()); // overrun, like directserial
|
||||
//
|
||||
// OVERRUN SEMANTICS. directserial drains its whole
|
||||
// backlog here (`while (doReceive());`) because a real
|
||||
// port's backlog is bounded by the physical line rate
|
||||
// -- there is never much to drain. A NAMED PIPE has no
|
||||
// such bound: vRIO can have hundreds of bytes queued,
|
||||
// and this loop teleported all of them into the UART in
|
||||
// zero guest-time, each one raising receive/line-status
|
||||
// state with no instruction executed in between.
|
||||
//
|
||||
// That burst is the trigger for the pod's residual
|
||||
// page fault (2026-07-29): it fires only when the guest
|
||||
// is briefly slow to read -- which is the mission-load
|
||||
// window -- and its probability moves with anything
|
||||
// that changes guest timing, which is why our own COM3
|
||||
// logging SUPPRESSED it (quiet conf 3/3 faults vs the
|
||||
// logged conf's 25-40%).
|
||||
//
|
||||
// TESTED, NOT THE CULPRIT (2026-07-29). Bounding the
|
||||
// drain to one byte -- real UART overrun semantics,
|
||||
// where the ARRIVING byte overwrites the unread one
|
||||
// rather than pulling the whole line forward -- did NOT
|
||||
// stop the fault (2/2 faults with it in place). The
|
||||
// measurement that explains why: overruns DURING a run
|
||||
// are only 1-3 per report period, because vRIO sends
|
||||
// about one byte every 1-3ms, so the backlog is shallow
|
||||
// and this loop never had hundreds to teleport. The
|
||||
// big 494/499 counts in the logs all land AFTER the
|
||||
// game exits.
|
||||
//
|
||||
// So the drain-all default stays -- it is the validated
|
||||
// directserial behaviour the RIO's rxpollus/rxburst
|
||||
// tuning was calibrated against, and changing it
|
||||
// without evidence would risk the real-cockpit timing
|
||||
// for nothing. VPX_RX_OVERRUN_ONE=1 opts into the
|
||||
// bounded form if a future experiment wants it.
|
||||
//
|
||||
static int overrun_one = -1;
|
||||
if (overrun_one < 0)
|
||||
overrun_one = getenv("VPX_RX_OVERRUN_ONE") ? 1 : 0;
|
||||
if (!overrun_one) { while (doReceive()); }
|
||||
rx_state = P_RX_WAIT;
|
||||
setEvent(SERIAL_RX_EVENT, bytetime * 0.9f / rx_burst_div);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user