2010-01-27 8 views
21

en Python 2.6 sous Linux, je peux utiliser ce qui suit pour traiter un signal TERM:Python - piège tous les signaux

import signal 
def handleSigTERM(): 
    shutdown() 
signal.signal(signal.SIGTERM, handleSigTERM)  

Est-il possible de configurer un gestionnaire pour tous les signaux reçus par le processus, autre que juste les mettre en place un-à la fois?

+4

La réponse que je crois va être "non" et certains signaux ne peuvent même pas être piégés (SIGKILL). –

Répondre

25

Vous pouvez simplement faire défiler les signaux dans le module de signaux et les configurer.

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)) 
+0

Juste ce que je cherchais, merci! –

+0

De rien. Merci d'avoir corrigé l'erreur dans le programme. :) –

+4

Cela devrait être RuntimeError, pas RunTimeError. ne pouvait pas modifier, comme un seul changement de personnage. – tobych

10

Si vous voulez vous débarrasser de l'essayer, juste ignorer les signaux qui ne peuvent pas être attrapés.

#!/usr/bin/env python 
# https://stackoverflow.com/questions/2148888/python-trap-all-signals 
import os 
import sys 
import time 
import signal 

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \ 
    for n in dir(signal) if n.startswith('SIG') and '_' not in n) 


def receive_signal(signum, stack): 
    if signum in [1,2,3,15]: 
     print 'Caught signal %s (%s), exiting.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum)) 
     sys.exit() 
    else: 
     print 'Caught signal %s (%s), ignoring.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum)) 

def main(): 
    uncatchable = ['SIG_DFL','SIGSTOP','SIGKILL'] 
    for i in [x for x in dir(signal) if x.startswith("SIG")]: 
     if not i in uncatchable: 
      signum = getattr(signal,i) 
      signal.signal(signum,receive_signal) 
    print('My PID: %s' % os.getpid()) 
    while True: 
     time.sleep(1) 
main() 
+0

Le code n'est pas correctement indenté mais je ne peux pas l'éditer car SO ne me laisse pas faire une modification aussi petite. Tout le pour devrait être indenté avec un niveau d'indentation moins. – krenel00

-1

Ce code ne fonctionnera pas dans la version actuelle de python. Il y a beaucoup de variables commençant par SIG avec la même valeur. Par exemple, SIGHUP et SIG_UNBLOCK sont tous les deux 1. La seule façon dont je pouvais penser à obtenir une liste de signaux réels était de le faire moi-même.

from signal import *  
signals = { 
     SIGABRT: 'SIGABRT', 
     SIGALRM: 'SIGALRM', 
     SIGBUS: 'SIGBUS', 
     SIGCHLD: 'SIGCHLD', 
     SIGCONT: 'SIGCONT', 
     SIGFPE: 'SIGFPE', 
     SIGHUP: 'SIGHUP', 
     SIGILL: 'SIGILL', 
     SIGINT: 'SIGINT', 
     SIGPIPE: 'SIGPIPE', 
     SIGPOLL: 'SIGPOLL', 
     SIGPROF: 'SIGPROF', 
     SIGQUIT: 'SIGQUIT', 
     SIGSEGV: 'SIGSEGV', 
     SIGSYS: 'SIGSYS', 
     SIGTERM: 'SIGTERM', 
     SIGTRAP: 'SIGTRAP', 
     SIGTSTP: 'SIGTSTP', 
     SIGTTIN: 'SIGTTIN', 
     SIGTTOU: 'SIGTTOU', 
     SIGURG: 'SIGURG', 
     SIGUSR1: 'SIGUSR1', 
     SIGUSR2: 'SIGUSR2', 
     SIGVTALRM: 'SIGVTALRM', 
     SIGXCPU: 'SIGXCPU', 
     SIGXFSZ: 'SIGXFSZ', 
     } 

for num in signals: 
    signal(num, h) 
+0

Ce n'est pas nécessaire. Tous les signaux commencent toujours par 'SIG', mais vous devez ajouter une double vérification pour vous assurer que vous ignorez les' SIG_'. –

8

Au Python 3.5, les constantes de signal sont defined as an enum, ce qui permet une plus belle approche:

import signal 

catchable_sigs = set(signal.Signals) - {signal.SIGKILL, signal.SIGSTOP} 
for sig in catchable_sigs: 
    signal.signal(sig, print) # Substitute handler of choice for `print` 
+0

Puis-je laisser un commentaire? Y at-il un problème avec cette réponse? – doctaphred

1

Voici un 2/3 de manière compatible qui ne dispose pas d'autant les pièges que les autres:

from itertools import count 
import signal 

def set_all_signal_signals(handler): 
    """Set all signals to a particular handler.""" 
    for signalnum in count(1): 
     try: 
      signal.signal(signalnum, handler) 
      print("set {}".format(signalnum)) 
     except (OSError, RuntimeError): 
      # Invalid argument such as signals that can't be blocked 
      pass 
     except ValueError: 
      # Signal out of range 
      break 

Puisque signalnum est simplement un nombre, passez de 1 à hors de portée en réglant le signal sur un descripteur particulier.

Questions connexes