Repository navigation
IDLE: in shell, time.sleep ignores _thread.interrupt_main() #74112
Description
Activity
Consider the following code, typed interactively:
>> import time
>> time.sleep(1e6)This will sleep for a bit over one and a half weeks. If this was typed in error, you may want to interrupt it. If using the command line, this is easy: just use Ctrl-C. If using IDLE, Ctrl-C has no effect. One could attempt to restart the shell with Ctrl-F6, which seems to work, but in fact the process remains in the background, hung until the timeout expires. There are two obvious workarounds: one is to sleep in a separate thread, so as to avoid blocking the main thread, and the other is to use a loop with smaller sleep increments:
for ii in range(1e5): sleep(10)
Now it only takes 10 seconds to interrupt a sleep. But these are both clumsy workarounds. They're so clumsy that I think I'm not going to use IDLE for this particular program and just use python -I. Would be nice if this were fixed.
I verified on Win 10 with 3.6.1. What system are you running on?
An automatic unittest test would be nice, but I cannot imagine how to write one. Even a human-verified htest (IDLE private term) would be good. Maybe I should write a live-interaction test script.
^C is bound to pyshell.PyShell.cancel_callback. When code is executing, this calls pyshell.ModifiedInterpreter.interrupt_subprocess. In a new thread, this starts pyshell.ModifiedInterpreter.__request_interrupt. I verified the calls thus far, with debug prints, while the user execution thread is sleeping. __request_interrupt sends vua rpc ('exec', 'interrupt_the_server').
'interrupt_the_server' refers to a method of run.Executor:
if interruptable:
_thread.interrupt_main()Here I am unsure which thread this executes in and when. Interrupting "while True: a=1" is no problem. Does interrup_main not work while the main thread is sleeping, or does the above not get executed?
- added3.7 (EOL)end of lifeend of lifetype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Mar 28, 2017 Scratch my confusion. I added "print('after')" immediately after _thread.interrupt_main() in idlelib.run.Executor.interrupt_the_server() and 'after' is printed in Shell right after I hit ^C but a time.sleep(10) is not immediately interrupted and 'KeyboardInterrupt' does not show for nearly 10 seconds. I don't know if this is a bug or unavoidable limitation not mentioned in the _thread doc. I might be system dependent.
https://docs.python.org/3/library/_thread.html#_thread.interrupt_main- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directoryand removed3.7 (EOL)end of lifeend of life
on Mar 28, 2017 - changed the title
[-]time.sleep ignores keyboard interrupt in IDLE[/-][+]time.sleep ignores _thread.interrupt_main()[/+]on Mar 28, 2017 It's simple to fix this in Python 3 on Windows. PyErr_SetInterrupt in Modules/signalmodule.c needs the following addition:
#ifdef MS_WINDOWS SetEvent(sigint_event); #endif
In the main thread on Windows, time.sleep() waits on this event.
On Unix, time.sleep() uses select(). We could interrupt it by signaling the process, or explicitly the main thread, via kill() or pthread_kill(). See bpo-21895 (#66094) for a related discussion.
Eryk, would the addition go before or after "trip_signal(SIGINT);"
I posted "Issue with _thread.interrupt_main (29926)" on pydev list. Steven D'Aprano verified delayed response on *nix.
Martin Panter said
"Looking at the implementation, _thread.interrupt_main just calls PyErr_SetInterrupt. It doesn’t appear to send a signal. I played with “strace” and couldn’t see any evidence of a signal. I guess it just sets a flag that will be polled. To actually interrupt the “sleep” call, you might need to use “pthread_kill” or similar (at least on Unix)."37 remaining items
I made Louie's patch a draft pending experimenting with other changes.
I am not terribly concerned about accidental long sleeps. I may investigate shell restart leaving a zombie process and whether interrupt failure could result in a restart popup.
The two comments I deleted were redundant here on github.
#157662 sends a real SIGINT to the main thread of the user process (
signal.pthread_kill(), orsignal.raise_signal()on Windows) instead of calling_thread.interrupt_main(), sotime.sleep()and other blocking calls are interrupted. It also fixes the deadlock ininput()observed in #2466: the interrupted wait for a response now releases its lock. The signal is sent while holding a new lock which protects sending a message, otherwise the connection could be corrupted.- added 4 commits that reference this issue
on Sep 23, 2026 3.15 backport must be generated after prior 3.15 backports are merged after 3.15 branch is unblocked.
The new test failed on the AMD64 Windows Server 2022 NoGIL buildbot: https://buildbot.python.org/#/builders/1241/builds/9341
The new test failed on the AMD64 Windows Server 2022 NoGIL buildbot: https://buildbot.python.org/#/builders/1241/builds/9341
@encukou This should be fixed by gh-158914: the test started the SIGINT timer before entering
assertRaises(), so on a loaded machine the interrupt could arrive outside the block.Thanks, @christianaurichzm.
Reacted by Christian Aurich Zanettini Martins
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
- StatusShow more project fieldsDone
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs