Repository navigation
fix(debugger): cancel timed-out commands on dump sessions - #138
Merged
Merged
Conversation
A command that outran its timeout was only cancelled on a live target, on the
reasoning that a dump has nothing to break into. The engine is still executing
the command though, so on a dump it ran to completion while every command sent
after it queued behind it and timed out in turn. The session was wedged until
closed, which is easy to reach now that open_kd_dump exists: a `!process 0 7`
over a large kernel dump runs for minutes.
Every session now gets its own process group, so CTRL+BREAK can be aimed at it
alone, and the cancel is no longer gated on the session being live. The engine
reports "User interrupted operation" and returns to the prompt.
Measured on a real dump with a 3 second timeout, before and after:
before: the command timed out, then `.lastevent` timed out too after 20s
with "(session may need a manual break-in)" - advice a dump user
cannot follow, because send_ctrl_break rejects a dump session
after: the command is cancelled in 3.0s and `.lastevent` returns in 0.0s
If the cancel does not resync, the two kinds now differ, because their recovery
options do. A live target keeps its session and the manual break-in hint, since
send_ctrl_break accepts it. A dump has no way back, so the session is closed
rather than left wedged with output that can no longer be attributed to the
command that produced it.
On the Unicode-log path the markers of abandoned commands are remembered so
their segments are stepped over instead of leading the next command's reply.
That list is bounded: a marker whose command never answers would otherwise sit
at its head and the list would grow with every timeout.
Not taken from the original change: the stray-break absorb. Its premise was
that a break reaching an idle debugger stays pending and aborts the next real
command. Measured, such a break is dropped, and the only command at risk is one
starting within about 10ms of the signal, which the absorb did not reliably
prevent either. In practice the next command arrives after a model round trip.
This was referenced Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #124, whose diagnosis and mechanism this takes.
The defect
A command that outran its timeout was only cancelled on a live target, on the reasoning that a dump has nothing to break into. But the engine is still executing the command, so on a dump it ran to completion while every later command queued behind it and timed out as well. The session was wedged until closed. Easy to reach now that
open_kd_dumpexists:!process 0 7over a large kernel dump runs for minutes.Measured on a real
cdbagainst a committed dump, 3 second timeout:The old hint was unfollowable for a dump user anyway:
_require_live_sessionrejectssend_ctrl_breakon a dump session.What changed
Every session gets its own process group, so CTRL+BREAK can be aimed at it alone, and the cancel is no longer gated on
is_live_session. The engine reports "User interrupted operation" and returns to the prompt.On a failed resync the two kinds now differ, because their recovery options do. A live target keeps its session and the manual break-in hint, since
send_ctrl_breakaccepts it. A dump has no way back, so the session is closed rather than left wedged with output that can no longer be attributed to the command that produced it.On the Unicode-log path the markers of abandoned commands are remembered so their segments are stepped over rather than leading the next command's reply. That list is bounded, since a marker whose command never answers would otherwise sit at its head while the list grew with every timeout.
What was deliberately left out
#124 also added a stray-break "absorb": a no-op
.echoafter a successful resync, on the premise that a break reaching an idle debugger stays pending and aborts the next real command. Measured, such a break is dropped, not pended. The only command at risk is one starting within about 10ms of the signal, and with the absorb in place 3 of 12 such commands were still truncated, so it did not close the window it targeted. In practice the next command arrives after a model round trip. That is about 25 source and 16 test lines not carried.Also corrected: the comments referenced issues #449 and #468, which do not exist in this repository.
Tests
Baseline before this change is 198 passed. The three added are the hybrid close for each session kind, plus
test_dump_cancel_live.py: a real-engine check that a busy loop on a dump session is cancelled and the next command returns in under 5 seconds. That one matters, because whether CTRL+BREAK cancels a command the engine is executing on a static dump is a property ofcdb, not of our fake, and the hermetic suite cannot tell. It carries thelivemarker, so it runs in CI and is deselected by-m "not live".Credit
The diagnosis, the reproduction and the cancel mechanism are @robster7674's, from #124.