Обработчик Python SIGTERM не активирован в подпроцессе

#python #linux #libc

#python #linux #libc

Вопрос:

Я хочу изящно освободить некоторый дорогостоящий системный ресурс в своем коде с помощью обработчика событий. Проблема в том, что обработчик событий зарегистрирован в разветвленном подпроцессе (да, я должен поместить обработчик событий туда в подпроцесс, поскольку ресурс выделяется после fork), и я хочу, чтобы подпроцессы завершались, когда родительский процесс умирает. Однако код работает не так, как я ожидал.

Вот доступный для выполнения пример:

 import time
import os
import signal

PRCTL=None
# get prctl from libc
def getPRCTL():
    global PRCTL
    if PRCTL is None:
        import ctypes
        PRCTL = ctypes.CDLL("libc.so.6")["prctl"]

    return PRCTL

def dieWithParent():
    prctl = getPRCTL()
    prctl(1, signal.SIGTERM)    # 1 = PR_SET_PDEATHSIG

def foo():
    print "In foo."

    def handler(signo, frame):
        print "Handler is activated."

    signal.signal(signal.SIGTERM, handler)

    time.sleep(10)    # in case sub-process terminates first.

if __name__ == '__main__':
    dieWithParent()
    pid = os.fork()
    if 0 == pid:
        foo()
    else:
        print "Subprocess spawned."
        print "dying..."
  

Код выполняет следующее:

  1. прикажите ОС превратить родительский сигнал матрицы в SIGTERM;
  2. разветвляйте подпроцесс;
  3. если дочерний процесс, зарегистрируйте обработчик сигналов и дождитесь завершения родительского процесса.

На моей платформе вывод

 $ python main.py
In foo.
Subprocess spawned.
dying...
  

Кажется, обработчик не активирован.

Что-то не так с моим кодом или пониманием?

Конфигурация на моем поле

2.6.18-238.el5 x86_64 Python 2.6

Любые подсказки будут высоко оценены, спасибо!

Ответ №1:

из prctl

PR_SET_PDEATHSIG (начиная с Linux 2.1.57) Устанавливает для сигнала смерти родительского процесса вызывающего процесса значение arg2 (либо значение сигнала в диапазоне 1..maxsig, либо 0 для очистки). Это сигнал, который вызывающий процесс получит, когда его родитель умрет. Это значение очищается для дочернего элемента fork(2) и (начиная с Linux 2.4.36 / 2.6.23) при выполнении двоичного файла set-user-ID или set-group-ID.

таким образом, вы, по сути, гарантируете, что ваш родитель умирает вместе со своим родителем, но ничего не говорите о своем дочернем процессе.

если вы добавите:

 dieWithParent()
  

после того, как вы разветвляете, он ведет себя правильно

Ответ №2:

Если это попытка написать демон, вам следует посмотреть двойное разветвление.

Например: http://code.activestate.com/recipes/66012-fork-a-daemon-process-on-unix /