This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, jpe, steve.dower, tim.golden, zach.ware
Date 2015-04-15.20:27:25
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1429129646.09.0.791349241908.issue23948@psf.upfronthosting.co.za>
In-reply-to
Content
> Which python level signal handler will CTRL_BREAK_EVENT 
> trigger?

The CRT maps it to a non-standard signal, SIGBREAK (21). It's defined in the signal module.

> GenerateConsoleCtrlEvent has different limitations for 
> CTRL_BREAK_EVENT and CTRL_C_EVENT according to MSDN; 
> I was referring to the CTRL_C_EVENT limitations.  

When creating a process group, the ConsoleFlags value in the process parameters is set to ignore CTRL_C_EVENT. You'll still get a DBG_CONTROL_C exception if a debugger is attached, but otherwise kernel32!CtrlRoutine ignores Ctrl+C. As you say, the docs state that "[CTRL_C_EVENT] cannot be generated for process groups". But it *does* work if you remove the ignore flag. This flag gets set/unset by assigning/removing a NULL handler.

Here's a revised example to enable Ctrl+C in the child, disable Python's INT handler, and then generate CTRL_C_EVENT to kill the child and verify that the exit code is STATUS_CONTROL_C_EXIT.

    import os
    import sys
    import signal
    import subprocess
    import threading

    STATUS_CONTROL_C_EXIT = 0xC000013A

    p = subprocess.Popen([sys.executable, '-i', '-c',
                          'import ctypes, signal;'
                          'kernel32 = ctypes.windll.kernel32;'
                          'kernel32.SetConsoleCtrlHandler(None, 0);'
                          'signal.signal(signal.SIGINT, signal.SIG_DFL)'],
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
    p.stderr.read(1) # poor man's WaitForInputIdle

    os.kill(p.pid, signal.CTRL_C_EVENT)
    watchdog = threading.Timer(5, p.terminate)
    watchdog.start()
    exitcode = p.wait()
    watchdog.cancel()

    if exitcode < 0:
        exitcode += 2 ** 32
    assert exitcode == STATUS_CONTROL_C_EXIT
History
Date User Action Args
2015-04-15 20:27:26eryksunsetrecipients: + eryksun, jpe, tim.golden, zach.ware, steve.dower
2015-04-15 20:27:26eryksunsetmessageid: <1429129646.09.0.791349241908.issue23948@psf.upfronthosting.co.za>
2015-04-15 20:27:26eryksunlinkissue23948 messages
2015-04-15 20:27:25eryksuncreate