[python-win32] Catching SIGBREAK with Python 3.3

Stefan Scherfke stefan at sofa-rockers.org
Mon Nov 12 14:12:20 CET 2012


Hi all,

recently I’ve been playing around with sending and catching signals on
Windows. I finally found out how to send and catch a BREAK event.

With Python 2.7(.2), I only need os.kill(pid, signal.CTRL_C_EVENT) and
signal.signal(signal.SIGBREAK, handler). Alternatively, I can use 
GenerateConsoleCtrlEvent and SetConsoleCtrlHandler via ctypes.

However, the former does not work with Python 3.3 (64bit) and the latter 
always raises a KeyError in Python’s threading module.

My question is: Should signal.signal(signal.SIGBREAK, handler) work 
under Python 3.3? If so, what am I doing wrong? Why raises the
ctypes-variant an error while the signal-variant doesn’t?

Below is a minimal example illustrating my problem:

# sigterm_min.py
import os
import signal
import subprocess
import sys
import time


WIN = (sys.platform == 'win32')
kwargs = {}
if WIN:
     kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP


def parent():
     proc = subprocess.Popen(['python', 'sigterm_min.py', 'child'], 
**kwargs)
     time.sleep(1)

     if WIN:
         # This works on Python 2.7 and 3.3:
         os.kill(proc.pid, signal.CTRL_BREAK_EVENT)

         # Alternative (ugly) way:
         # import ctypes
         # ctypes.windll.kernel32.GenerateConsoleCtrlEvent(
         #         signal.CTRL_BREAK_EVENT, proc.pid)
     else:
         proc.terminate()

     print('parent waiting for child')
     proc.wait()
     print('parent terminating')


def child():
     def handler(signum, frame=None):
         print('child terminating')
         sys.exit(0)

     if WIN:
         # This only works on Python 2.7, but not on 3.3:
         signal.signal(signal.SIGBREAK, handler)

         # (Ugly) alternative that works on both Python 2.7 and 3.3,
         # but raises a KeyError in threading.py:
         # import ctypes
         # handler = ctypes.WINFUNCTYPE(ctypes.c_int,
         #                              ctypes.c_uint)(handler)
         # ctypes.windll.kernel32.SetConsoleCtrlHandler(handler, True)
     else:
         signal.signal(signal.SIGTERM, handler)

     time.sleep(10)


if __name__ == '__main__':
     if len(sys.argv) == 1:
         parent()
     elif sys.argv[1] == 'child':
         child()
# EOF

Cheers,
Stefan


More information about the python-win32 mailing list