serial write hardening: bound the overlapped-write wait (500ms + CancelIo + 3s sick window) -- a dropped USB-serial link parked the game forever in GetOverlappedResult (ALPHA-MR minidump: SendPacket <- RIO ctor); txTO= counter joins the [rio] health line
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ab1b3439f4
commit
716e10e3fa
@@ -410,6 +410,20 @@ int PCSerialPacket::ReceivePacket(BYTE *destPtr) // returns len (zero if none)
|
||||
// Returns:
|
||||
// void
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Serial-write health (see the bounded wait below): after a write timeout
|
||||
// the link is SICK for 3 s and writes fast-drop -- one stall, not one per
|
||||
// poll. BTPcspakTxTimeouts feeds the [rio] telemetry.
|
||||
//
|
||||
static unsigned gPcspakTxTimeout = 0;
|
||||
static DWORD gPcspakTxSickUntil = 0;
|
||||
|
||||
extern "C" unsigned
|
||||
BTPcspakTxTimeouts()
|
||||
{
|
||||
return gPcspakTxTimeout;
|
||||
}
|
||||
|
||||
void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
@@ -418,6 +432,11 @@ void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
||||
if(!enabled) //if disabled, don't even try
|
||||
return;
|
||||
|
||||
if (gPcspakTxSickUntil != 0 && GetTickCount() < gPcspakTxSickUntil)
|
||||
{
|
||||
return; // adapter sick: drop, don't stall
|
||||
}
|
||||
|
||||
BYTE cmd = *srcPtr; //get the command byte
|
||||
cmd &= 0x7F; //remove MSB
|
||||
int length = txLengthPtr[cmd]; //get the length in al
|
||||
@@ -459,11 +478,37 @@ void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
||||
return;
|
||||
}
|
||||
}
|
||||
DWORD bytesWritten;
|
||||
GetOverlappedResult(hComm, &overlapSend, &bytesWritten, TRUE);
|
||||
if(bytesWritten != length + 1)
|
||||
//
|
||||
// BOUNDED completion wait (2026-08-10, ALPHA-MR field minidump). The
|
||||
// RIO's "COM1" is a USB-serial adapter; when its USB link drops with a
|
||||
// write in flight the overlapped write NEVER completes, and the original
|
||||
// GetOverlappedResult(..., TRUE) parked the whole game at 0 CPU forever
|
||||
// (cdb-proven: NtWaitForSingleObject <- GetOverlappedResult <-
|
||||
// SendPacket <- RIO ctor). Now: 500 ms bound (9600 baud needs ~21 ms),
|
||||
// CancelIo on expiry, and a 3 s SICK window that fast-drops writes so a
|
||||
// dead adapter costs one stall, not one per 50 ms poll -- the game stays
|
||||
// at frame rate with a degraded RIO and the keyboard fallback alive.
|
||||
// gPcspakTxTimeout feeds the [rio] health line (txTO=).
|
||||
//
|
||||
DWORD bytesWritten = 0;
|
||||
DWORD wait_result = WaitForSingleObject(overlapSend.hEvent, 500);
|
||||
if (wait_result == WAIT_OBJECT_0)
|
||||
{
|
||||
DEBUG_STREAM << "Not all data was written to serial port!\n" << std::flush;
|
||||
GetOverlappedResult(hComm, &overlapSend, &bytesWritten, FALSE);
|
||||
gPcspakTxSickUntil = 0;
|
||||
if (bytesWritten != (DWORD)(length + 1))
|
||||
{
|
||||
DEBUG_STREAM << "Not all data was written to serial port!\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No print here -- serial-path discipline; the counter surfaces in
|
||||
// the [rio] health line (txTO=) from the glass-tick printer.
|
||||
CancelIo(hComm);
|
||||
++gPcspakTxTimeout;
|
||||
gPcspakTxSickUntil = GetTickCount() + 3000;
|
||||
}
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user