Skip to content

IDLE: in shell, time.sleep ignores _thread.interrupt_main() #74112

Description

@Mark
mannequin
BPO 29926
Nosy @terryjreedy, @pitrou, @njsmith, @vadmium, @eryksun, @mlouielu
PRs
  • gh-74112: IDLE: Fix blocking function ignore SIGINT #2466
  • Files
  • int-unix.patch
  • 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:

    assignee = 'https://github.com/terryjreedy'
    closed_at = None
    created_at = <Date 2017-03-27.22:51:11.745>
    labels = ['expert-IDLE', 'type-bug', '3.9']
    title = 'IDLE: in shell, time.sleep ignores _thread.interrupt_main()'
    updated_at = <Date 2019-09-19.18:42:59.551>
    user = 'https://bugs.python.org/Mark'

    bugs.python.org fields:

    activity = <Date 2019-09-19.18:42:59.551>
    actor = 'terry.reedy'
    assignee = 'terry.reedy'
    closed = False
    closed_date = None
    closer = None
    components = ['IDLE']
    creation = <Date 2017-03-27.22:51:11.745>
    creator = 'Mark'
    dependencies = []
    files = ['46771']
    hgrepos = []
    issue_num = 29926
    keywords = ['patch']
    message_count = 31.0
    messages = ['290663', '290675', '290677', '290679', '290715', '290728', '290743', '290744', '290749', '290751', '290761', '291049', '291052', '291054', '297157', '297163', '297176', '297241', '297242', '297286', '297288', '297291', '297307', '297323', '297330', '297334', '297345', '297347', '297349', '297352', '297477']
    nosy_count = 7.0
    nosy_names = ['terry.reedy', 'pitrou', 'njs', 'martin.panter', 'Mark', 'eryksun', 'louielu']
    pr_nums = ['2466']
    priority = 'normal'
    resolution = None
    stage = 'needs patch'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue29926'
    versions = ['Python 3.9']

    Linked PRs

    Activity

    1. Mark commented on Mar 27, 2017

      Markmannequin
      MannequinAuthor

      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.

    2. terryjreedy commented on Mar 28, 2017

      @terryjreedy
      Member

      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?

    3. terryjreedy commented on Mar 28, 2017

      @terryjreedy
      Member

      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

    4. added
      stdlibStandard Library Python modules in the Lib/ directory
      and removed on Mar 28, 2017
    5. removed their assignment
      on Mar 28, 2017
    6. changed the title [-]time.sleep ignores keyboard interrupt in IDLE[/-] [+]time.sleep ignores _thread.interrupt_main()[/+] on Mar 28, 2017
    7. eryksun commented on Mar 28, 2017

      @eryksun
      Contributor

      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.

    8. terryjreedy commented on Mar 28, 2017

      @terryjreedy
      Member

      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)."

    9. 37 remaining items

    10. terryjreedy commented on Feb 4, 2023

      @terryjreedy
      Member

      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.

    11. serhiy-storchaka commented on Sep 17, 2026

      @serhiy-storchaka
      Member

      #157662 sends a real SIGINT to the main thread of the user process (signal.pthread_kill(), or signal.raise_signal() on Windows) instead of calling _thread.interrupt_main(), so time.sleep() and other blocking calls are interrupted. It also fixes the deadlock in input() 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.

    12. added 4 commits that reference this issue on Sep 23, 2026
    13. terryjreedy commented on Sep 27, 2026

      @terryjreedy
      Member

      3.15 backport must be generated after prior 3.15 backports are merged after 3.15 branch is unblocked.

    14. encukou commented on Oct 6, 2026

      @encukou
      Member

      The new test failed on the AMD64 Windows Server 2022 NoGIL buildbot: https://buildbot.python.org/#/builders/1241/builds/9341

    15. christianaurichzm commented on Oct 6, 2026

      @christianaurichzm
      Contributor

      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.

    16. added 2 commits that reference this issue on Oct 6, 2026
    17. serhiy-storchaka commented on Oct 6, 2026

      @serhiy-storchaka
      Member
    18. added a commit that references this issue on Oct 6, 2026
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    topic-IDLEtype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions