You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Windows: remote pdb loses its interrupt connection after about 120 seconds #160683
Attach from another terminal using the same build typing python -m pdb -p <PID>
Enter c, wait 135 seconds, then interrupt from the debugger client (Ctrl+C)
The expected result should be the target stopping and another debugger prompt appearing.
But in this case the target's listener thread fails in sock.recv(1024) with ConnectionResetError: [WinError 10054]. Forwarding the subsequent client
interrupt fails in self.interrupt_sock.sendall(...) with ConnectionAbortedError: [WinError 10053]. The target application keeps running.
Confirmed in two automated real pdb.attach() / sys.remote_exec() sessions,
raising SIGINT in the client after 135 seconds. Removing only sock.shutdown(socket.SHUT_WR) from _PdbServer._start_signal_listener() in
memory made both control runs succeed, including variable evaluation and
detach after the interrupt.
The regular test_remote_pdb still passes (47 passed, 2 skipped), since
its interrupt test does not wait for this tested 120 second idle interval.
Root cause is likely the half-close at Lib/pdb.py:3009: the client only writes to that socket (Lib/pdb.py:3517), so shutdown(SHUT_WR) buys nothing and parks the connection in FIN_WAIT_2, which Windows reaps after TcpFinWait2Delay (120 s).
Plain sockets reproduce it without CPython: FIN_WAIT_2 at t=0, then at exactly 120.0 s recv → 10054 and the peer's sendall → 10053, the same pair you saw.
Dropping that one call fixes it locally: test_remote_pdb and test_pdb pass (289 run), and a new test that asserts the interrupt socket never sees EOF fails on main and passes with the change.
Want me to send the PR?
I went looking for the rationale, since it decides whether the call can be dropped.
git log -S "SHUT_WR" -- Lib/pdb.py finds two commits. It first appears in 5993e06 ("Use a thread to manage interrupts on Windows") and only moves in dd7c9b1. 5993e06 is the first version of the listener, its commit message does not mention the shutdown, and #133223 has no review or conversation comment about it.
In 5993e06 the client already did nothing but sendall() on this socket, the same as today (Lib/pdb.py:3517). So no code ever read the EOF that the half-close produces. Either it was meant to document that the channel is one-way, or it is vestigial.
If there is a reason I cannot see from the history, it settles the question. Otherwise I suggest dropping the call and keeping the test that asserts this socket never sees EOF.
Activity
summeriver13 commentedon Oct 26, 2026
Root cause is likely the half-close at
Lib/pdb.py:3009: the client only writes to that socket (Lib/pdb.py:3517), soshutdown(SHUT_WR)buys nothing and parks the connection in FIN_WAIT_2, which Windows reaps afterTcpFinWait2Delay(120 s).Plain sockets reproduce it without CPython: FIN_WAIT_2 at t=0, then at exactly 120.0 s
recv→ 10054 and the peer'ssendall→ 10053, the same pair you saw.Dropping that one call fixes it locally:
test_remote_pdbandtest_pdbpass (289 run), and a new test that asserts the interrupt socket never sees EOF fails on main and passes with the change.Want me to send the PR?
cfbolz commentedon Oct 26, 2026
this was added in 9434709, @godlygeek, do you remember why the half-close is there?
summeriver13 commentedon Oct 26, 2026
I went looking for the rationale, since it decides whether the call can be dropped.
git log -S "SHUT_WR" -- Lib/pdb.pyfinds two commits. It first appears in 5993e06 ("Use a thread to manage interrupts on Windows") and only moves in dd7c9b1. 5993e06 is the first version of the listener, its commit message does not mention the shutdown, and #133223 has no review or conversation comment about it.In 5993e06 the client already did nothing but
sendall()on this socket, the same as today (Lib/pdb.py:3517). So no code ever read the EOF that the half-close produces. Either it was meant to document that the channel is one-way, or it is vestigial.If there is a reason I cannot see from the history, it settles the question. Otherwise I suggest dropping the call and keeping the test that asserts this socket never sees EOF.
godlygeek commentedon Oct 26, 2026
That was definitely the intention. If the half closed socket is getting timed out by the OS, we should definitely just stop half closing it.
pythongh-160683: Stop half-closing the remote debugging interrupt socket
pythongh-160683: Stop half-closing the remote debugging interrupt socket