gh-74112: Make Ctrl-C in the IDLE Shell interrupt blocking calls - #157662
Conversation
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.
|
@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
|
|
1, 2, and 3 interrupted as desired. VERY nice! For 4 and 5, restart worked fine. They are not things beginners are likely to do unless exploring the unknown. My main concern reviewing and merging is avoiding regressions. I used the debugger to exercise rpc in other ways and it seemed normal. I presume wrapping chunks of code in 'with lock:' should generally be safer, with a small time cost not noticeable here. |
|
You merged the _tkinter fix; merge this now? |
|
Note: ^C already worked (as on 3.15) for 2 and 3. time.sleep (1) requires this patch. I suspect same of some other cases. |
|
Perhaps just rerun macOS tests? EDIT I see you already reran tests |
|
Thanks @serhiy-storchaka for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15. |
|
Sorry, @serhiy-storchaka, I could not cleanly backport this to |
|
GH-158016 is a backport of this pull request to the 3.14 branch. |
|
GH-158017 is a backport of this pull request to the 3.13 branch. |
|
3.15 needs the _tkinter fix and maybe some other pending backports. |
…ls (GH-157662) (GH-158017) 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. (cherry picked from commit 9232c21) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…ls (GH-157662) (GH-158016) 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. (cherry picked from commit 9232c21) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
I made a note on my backport list. The IDLE project is not taking new entries today, so made a continuation list on my machine. |
_thread.interrupt_main()only sets a flag which is checked between bytecodes, so Ctrl-C did not interrupttime.sleep(),socket.recv()and other blocking calls. Now a real SIGINT is sent to the main thread of the user process: withsignal.pthread_kill(), or withsignal.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, andsocket.recv()(not interruptible on Windows, as in a console).🤖 Generated with Claude Code