Skip to content

gh-74112: Make Ctrl-C in the IDLE Shell interrupt blocking calls - #157662

Open
serhiy-storchaka wants to merge 1 commit into
python:mainfrom
serhiy-storchaka:gh-74112-interrupt-signal
Open

serhiy-storchaka wants to merge 1 commit into
python:mainfrom
serhiy-storchaka:gh-74112-interrupt-signal

Conversation

@serhiy-storchaka

Copy link
Copy Markdown
Member

_thread.interrupt_main() only sets a flag which is checked between bytecodes, so Ctrl-C did not interrupt time.sleep(), socket.recv() and other blocking calls. Now a real SIGINT is sent to the main thread of the user process: with signal.pthread_kill(), or with signal.raise_signal() on Windows, where the C signal handler wakes up the main thread. _thread.interrupt_main() is still used when SIGINT is not handled by Python.

Sending a message is now protected by a lock, and the signal is sent while holding it. Otherwise the main thread could be interrupted in the middle of a message, and the GUI process would wait for its end forever; this happened regularly on Windows during large output. An interrupted wait for a response now releases its lock, so that the socket thread does not deadlock (the problem observed in #2466).

Tested on Linux and Windows with time.sleep(), input(), loops with large output, and socket.recv() (not interruptible on Windows, as in a console).

🤖 Generated with Claude Code

Send a real SIGINT to the main thread of the user process instead of
calling _thread.interrupt_main(), which only sets a flag checked
between bytecodes.  The signal is sent while holding a new lock which
protects sending a message, so that the main thread is not interrupted
in the middle of a message.  An interrupted wait for a response now
releases its lock, so that the socket thread does not deadlock.
@serhiy-storchaka serhiy-storchaka added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes labels Sep 17, 2026
@serhiy-storchaka

Copy link
Copy Markdown
Member Author

@terryjreedy, to test manually: start IDLE, then in the Shell enter each of the following, wait a second, and press Ctrl-C. Each should print a KeyboardInterrupt traceback immediately and show a new prompt, and the Shell should keep working afterwards.

  1. import time; time.sleep(60) — before this PR, nothing happens for 60 s.
  2. input() — should not freeze IDLE.
  3. import sys and then while True: sys.stdout.write('x'*200000) (press Enter twice) — before this PR, on Windows this could freeze IDLE waiting for the end of a partially sent message.
  4. import socket; s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.bind(('127.0.0.1', 0)); s.recv(100) — interrupted on Linux and macOS; not on Windows, as in a console.
  5. import signal; signal.signal(signal.SIGINT, signal.SIG_IGN) and then time.sleep(10) — Ctrl-C is ignored, as before this PR and as in a console.

@serhiy-storchaka

Copy link
Copy Markdown
Member Author

The macOS failure is caused by Tk replacing Python's SIGINT handler with its own, which exits the process (#157672). #157673 fixes this in _tkinter; this PR should be merged after it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant