Python - Trap all signals
You could just loop through the signals in the signal module and set them up.
for i in [x for x in dir(signal) if x.startswith("SIG")]:
try:
signum = getattr(signal,i)
signal.signal(signum,sighandler)
except (OSError, RuntimeError) as m: #OSError for Python3, RuntimeError for 2
print ("Skipping {}".format(i))
How do I capture SIGINT in Python?
Register your handler with signal.signal
like this:
#!/usr/bin/env python
import signal
import sys
def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()
Code adapted from here.
More documentation on signal
can be found here.
Catching signals other than SIGINT in Python
POSIX specifies exactly two user defined signals:
SIGUSR1 = 30
SIGUSR2 = 31
These two signals aren't triggered by any action, meaning you can explicitly define handlers for these and raise these signals for your purpose.
import signal
def handler(signum):
if signum == signal.SIGUSR1:
print('user defined interrupt!')
signal.signal(signal.SIGUSR1, handler)
These signals have been provided explicitly for the user's purpose, so it would be a good idea to raise and handle these signals in your application.
To explicitly raise this signal with code, you would have to use:
import os
os.kill(os.getpid(), signal.SIGUSR1)
Where os.getpid()
returns the process ID of the current process. Replace this with the ID of the process you wish to kill (if it isn't the current one).
Also, I should mention that SIGUSR1/2
are not supported in Windows. The documentation mentions that besides SIGABRT
, SIGFPE
, SIGILL
, SIGINT
, SIGSEGV
, or SIGTERM
, no other signal can be raised. A ValueError will be raised in any other case.
Why Python subprocesses won't properly capture signals?
This is a race condition.
You are forking and immediately sending the signal, so it's a race for the child process to ignore it before it gets killed.
Furthermore, your parent script has a race condition in checking whether the script has died. You signal the script and immediately check if it's dead, so it's a race for the child to die before the check happens.
If you add a time.sleep(1)
before sending the signal, you'll make sure the child wins the race and therefore you get the behavior you expect.
python: catch SIGINT in process reading data from a socket
Looks like your internal loop is blocking progBreak
check, this code is working for me:
import signal
progBreak = False
def newBreakHandler(signum, frame):
global progBreak
progBreak = True
def runMain():
global progBreak
signal.signal(signal.SIGINT, newBreakHandler)
while not progBreak:
while not progBreak and client.poll():
command = client.recv_bytes()
print "Exiting..."
runMain()
How to process SIGTERM signal gracefully?
A class based clean to use solution:
import signal
import time
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, *args):
self.kill_now = True
if __name__ == '__main__':
killer = GracefulKiller()
while not killer.kill_now:
time.sleep(1)
print("doing something in a loop ...")
print("End of the program. I was killed gracefully :)")
Related Topics
What Do I Use on Linux to Make a Python Program Executable
Can Python Select What Network Adapter When Opening a Socket
How to Split a List into Equally-Sized Chunks
How to Remove Duplicates from a List, While Preserving Order
Evaluating a Mathematical Expression in a String
How to Read/Process Command Line Arguments
Multiprocessing VS Threading Python
How to Find All Occurrences of an Element in a List
How to Protect Python Code from Being Read by Users
How to Use Multiprocessing Pool.Map With Multiple Arguments
Calling a Python Script from Command Line Without Typing "Python" First
How to Pass a Variable by Reference
How to Serve Static Files in Flask
Why Do I Get Attributeerror: 'Nonetype' Object Has No Attribute 'Something'
How to Put a Variable'S Value Inside a String