Python - Ловушка всех сигналов

21

В python 2.6 под Linux я могу использовать следующее для обработки сигнала TERM:

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

Есть ли способ настроить обработчик для всех сигналов, полученных процессом, кроме как настроить их один раз в секунду?

    
задан Justin Ethier 27.01.2010 в 18:16
источник
  • Ответ, который, я считаю, будет «нет», и определенный сигнал не может быть захвачен (SIGKILL). –  Murali VP 27.01.2010 в 18:22

5 ответов

29

Вы можете просто пропустить сигналы в сигнальном модуле и настроить их.

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))
    
ответ дан Noufal Ibrahim 27.01.2010 в 18:24
  • Просто то, что я искал, спасибо! –  Justin Ethier 27.01.2010 в 18:51
  • Добро пожаловать. Спасибо за исправление ошибки в программе. :) –  Noufal Ibrahim 27.01.2010 в 18:54
  • Это должно быть RuntimeError, а не RunTimeError. не может редактировать, как только одно изменение персонажа. –  tobych 01.09.2011 в 06:14
  • Ваше понимание списка будет включать SIG_IGN, действие которого не является сигналом. Поскольку значение этого действия соответствует 1, что является значением SIGHUP, вы будете устанавливать этот сигнал дважды. Для этого конкретного случая это не имеет значения, однако этот код может разрушаться для других подобных целей. –  Bryce Guinta 16.05.2017 в 12:14
  • Этот ответ не применим к Python 3, так как попытка установить неблокируемые сигналы, такие как SIGKILL, например, теперь выдает OSError вместо RuntimeError. –  Bryce Guinta 16.05.2017 в 12:36
Показать остальные комментарии
10

Если вы хотите избавиться от попытки, просто игнорируйте сигналы, которые невозможно поймать.

#!/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()
    
ответ дан eric poelke 14.04.2011 в 22:06
  • Код не имеет должным образом отступ, но я не могу его отредактировать, потому что SO не позволяет мне сделать небольшое изменение. Все это должно быть отступом с одним уровнем отступов меньше. –  krenel00 10.05.2013 в 17:04
9

Как и в случае с Python 3.5, константы сигнала определены как перечисление , что позволяет более удобный подход:

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'
    
ответ дан doctaphred 02.01.2016 в 17:40
  • Может ли downvoter оставить комментарий? Что-то не так с этим ответом? –  doctaphred 23.04.2016 в 13:15
1

Вот 2/3 совместимый способ, который не имеет столько ловушек, как другие:

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

Так как signalnum - это просто число, переходите через 1 к вне диапазона, задавая сигнал определенному дескриптору.

    
ответ дан Bryce Guinta 16.05.2017 в 12:25
-1

Этот код не будет работать в текущей версии python. Существует много переменных, начиная с SIG с одинаковым значением. Например, SIGHUP и SIG_UNBLOCK равны 1. Единственный способ, которым я мог подумать, получить список фактических сигналов , должен был просто сделать это сам.

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)
    
ответ дан enigmaticPhysicist 12.03.2015 в 00:24
  • Это не обязательно. Все сигналы все еще начинаются с SIG, но вам нужно добавить двойную проверку, чтобы убедиться, что вы игнорируете SIG_. –  Noufal Ibrahim 26.05.2017 в 13:25