Reply to every debugger request, even the ones that finish later

Eight events answered nothing at all: cpu.stepping, cpu.resume, gpu.stats.feed
and the five stepping requests. Their documented contract was "no immediate
response, an event follows", which leaves a client unable to tell an accepted
request from one that was dropped - and forces any request/response
correlation to carry a hardcoded list of events that don't answer. wsdbg's
--sync doesn't have that list, so it waits for the next message and treats
whatever broadcast arrives first as the answer, silently misattributing every
later response in the script.

Fixed centrally in the dispatch loop rather than in the eight handlers: if a
handler finishes without having sent anything, send an empty response carrying
its ticket. That also covers handlers added later, which is the part a
per-handler fix wouldn't.

The asynchronous event that reports the real outcome is unchanged and still
follows. The two are easy to tell apart - the acknowledgement carries the
ticket from the request, a broadcast has none:

  -> {"event":"cpu.stepInto","ticket":3}
  <- {"event":"cpu.stepInto","ticket":3}
  <- {"event":"cpu.stepping","pc":142622896,"reason":"cpu.stepInto",...}

Existing clients ignore events they didn't ask for, and this adds a message
rather than changing or removing one, so nothing that worked before breaks.

pspautotests 314/314.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
Henrik Rydgård
2026-08-18 09:32:04 +02:00
co-authored by Claude Opus 5
parent 8120338530
commit ef426c8f82
5 changed files with 32 additions and 13 deletions
@@ -66,7 +66,8 @@ static DebugInterface *CPUFromRequest(DebuggerRequest &req) {
//
// No parameters.
//
// No immediate response. Once CPU is stepping, a "cpu.stepping" event will be sent.
// Response (same event name) with no extra data, acknowledging the request. The CPU may not be
// stepping yet at that point - a "cpu.stepping" event follows once it is.
void WebSocketCPUStepping(DebuggerRequest &req) {
if (!currentDebugMIPS->isAlive()) {
return req.Fail("CPU not started");
@@ -83,7 +84,8 @@ void WebSocketCPUStepping(DebuggerRequest &req) {
//
// No parameters.
//
// No immediate response. Once CPU is stepping, a "cpu.resume" event will be sent.
// Response (same event name) with no extra data, acknowledging the request. A "cpu.resume"
// event follows once the CPU is actually running again.
void WebSocketCPUResume(DebuggerRequest &req) {
if (!currentDebugMIPS->isAlive()) {
return req.Fail("CPU not started");