This is a follow up question to the following SO answer by @ErykSun: https://stackoverflow.com/a/35792192/1424462
In my use case, I want to use signals to terminate a console process in Python from another process (that is not its parent), by sending a signal. The Python process to be terminated needs to do some cleanup, and therefore would need to get control via the signal handler.
According to @ErykSun's answer (or at least according to my reading of it :-) that should be possible in Python on Windows using SIGINT or SIGBREAK.
However, I was unable to get that working on Windows.
I have written a short Python program for investigating which signals can be handled. To keep it simple, I am only covering the signal handling side in Python. The signal sending side is another topic maybe for later.
sighandler.py:
#!/usr/bin/env python
"""
Demonstrate signal handling in Python.
Usage:
- run this script, it will show the process ID
- send OS-level signals to the process ID of the script (e.g. 'kill -n 2 PID')
"""
import sys
import os
import platform
import signal
import time
SLEEP_TIME = 300
def sigstr(signal_number):
try:
return signal.strsignal(signal_number)
except AttributeError:
return '?'
class SignalIndication(Exception):
pass
def signal_handler(signal_number, frame):
print("handler: Received signal {} ({})".
format(signal_number, sigstr(signal_number)))
raise SignalIndication(
"signal {} ({})".format(signal_number, sigstr(signal_number)))
def register_handler(signal_name, condition=True):
if condition:
signal_number = getattr(signal, signal_name)
print("main: Registering handler for signal {} ({}, {})".
format(signal_number, signal_name, sigstr(signal_number)))
signal.signal(signal_number, signal_handler)
print("main: Python: {}".format(sys.version.replace('\n', '')))
print("main: Platform: {} / {}".format(sys.platform, platform.platform()))
print("main: Process: {}".format(os.getpid()))
register_handler('SIGINT')
register_handler('SIGILL')
register_handler('SIGABRT')
register_handler('SIGFPE')
register_handler('SIGSEGV')
register_handler('SIGTERM')
register_handler('SIGBREAK', sys.platform == 'win32')
while True:
print("main: Sleeping for {} sec".format(SLEEP_TIME))
try:
time.sleep(SLEEP_TIME)
except Exception as exc:
print("main: Caught {}: {}".format(exc.__class__.__name__, exc))
I have verified on macOS that it works as expected, I can use kill -n SIGNUM PID
successfully on all registered signals, and the handler gets control every time. I verified this on macOS with Python 2.7, 3.7, 3.9, for example:
$ ./sighandler.py
main: Python: 3.9.1 (default, Feb 1 2021, 20:41:56) [Clang 12.0.0 (clang-1200.0.32.29)]
main: Platform: darwin / macOS-10.15.7-x86_64-i386-64bit
main: Process: 30460
main: Registering handler for signal 2 (SIGINT, Interrupt: 2)
main: Registering handler for signal 4 (SIGILL, Illegal instruction: 4)
main: Registering handler for signal 6 (SIGABRT, Abort trap: 6)
main: Registering handler for signal 8 (SIGFPE, Floating point exception: 8)
main: Registering handler for signal 11 (SIGSEGV, Segmentation fault: 11)
main: Registering handler for signal 15 (SIGTERM, Terminated: 15)
main: Sleeping for 300 sec
# --> in another terminal: kill -n 2 30460
handler: Received signal 2 (Interrupt: 2)
main: Caught SignalIndication: signal 2 (Interrupt: 2)
main: Sleeping for 300 sec
# --> in another terminal: kill -n 9 30460
Killed: 9
On Windows, I have not gotten the script to handle a single signal so far.
For sending the "signals" on Windows, I have used windows-kill (choco install windows-kill
) to send the "signals" SIGINT and SIGBREAK, which actually send the CTRL_C_EVENT and the CTRL_BREAK_EVENT. The table below shows the result:
OS Python Sent by Signals Handler is
Win 7 2.7 windows-kill SIGINT,SIGBREAK not called
Win 7 3.7 windows-kill SIGINT,SIGBREAK not called
macOS 10 2.7 kill all in script called
macOS 10 3.7 kill all in script called
macOS 10 3.9 kill all in script called
My questions are:
- Did anyone get the SIGINT or SIGBREAK signals handled in Python on Windows, when the events are originated on another process on the same system? If so, please provide details.
- What change in the setup would make it work on Windows?