2010-07-12 2 views
13

Мой скрипт python перехватывает сигнал SIGINT сигналом процесс модуль для предотвращения преждевременного выхода, но этот сигнал передается подпроцессу, который я открываю с помощью Popen. есть ли способ предотвратить передачу этого сигнала в подпроцесс, чтобы он также не вышел преждевременно, когда пользователь нажимает ctrl-c?Как остановить передачу SIGINT на подпроцесс в python?

+0

На какой платформе вы работаете? – ChristopheD

+0

Я на Ubuntu linux. – shino

ответ

2

Вы можете повторно назначить роль ctrl-c с помощью модуля tty, который позволяет вам манипулировать назначением сигналов. Однако имейте в виду, что, если вы не вернете их так, как они были до того, как вы их измените, они будут сохраняться для всей сессии оболочки даже после выхода программы.

Вот простой фрагмент кода, чтобы вы начали, сохраняя старые настройки tty, переустанавливая ctrl-c на ctrl-x, а затем восстанавливая предыдущие настройки tty после выхода.

import sys 
import tty 

# Back up previous tty settings 
stdin_fileno = sys.stdin.fileno() 
old_ttyattr = tty.tcgetattr(stdin_fileno) 

try: 
    print 'Reassigning ctrl-c to ctrl-x' 

    # Enter raw mode on local tty 
    tty.setraw(stdin_fileno) 
    raw_ta = tty.tcgetattr(stdin_fileno) 
    raw_ta[tty.LFLAG] |= tty.ISIG 
    raw_ta[tty.OFLAG] |= tty.OPOST | tty.ONLCR 

    # ^X is the new ^C, set this to 0 to disable it entirely 
    raw_ta[tty.CC][tty.VINTR] = '\x18' 

    # Set raw tty as active tty 
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, raw_ta) 

    # Dummy program loop 
    import time 
    for _ in range(5): 
     print 'doing stuff' 
     time.sleep(1) 

finally: 
    print 'Resetting ctrl-c' 
    # Restore previous tty no matter what 
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, old_ttyattr) 
14

обработчики сигналов наследуются при запуске подпроцесс, так что если вы используете модуль сигнала игнорировать SIGINT (signal.signal(signal.SIGINT, signal.SIG_IGN)), то ваш дочерний процесс автоматически будет также.

Есть два важных предостережений, хотя:

  • Вы должны установить игнорировать обработчик перед тем вы икру дочерний процесс
  • Пользовательские обработчики сигналов сбрасываются на обработчики по умолчанию, так как дочерний процесс не будет иметь доступ к коду обработчика для его запуска.

Так что, если вам нужно настроить обработку SIGINT, а не просто игнорируя его, вы, вероятно, хотите, чтобы временно игнорировать SIGINT в то время как вы икру свой дочерний процесс, а затем (пере) установить свой собственный обработчик сигнала.

Если вы пытаетесь поймать SIGINT и установить флаг, чтобы вы могли выйти в безопасном месте, а не сразу, помните, что когда вы доберетесь до этой безопасной точки, вашему коду придется вручную очистить своих потомков, так как ваш дочерний процесс и любые запущенные процессы будут игнорировать SIGINT.

+0

Если это работает (что не всегда), это лучший вариант, чем сбрасывание терминала. – zwol

+0

Если вы используете fork()/exec() вместо popen(), вы можете выполнить SIG_IGN после fork() перед exec(). Это позволяет временно отключить обработчик родителя. Похоже, что будут условия гонки, независимо от того, что вы делаете, но способ fork()/exec() кажется немного более безопасным. Конечно, OP спрашивал о Popen от python, но этот вопрос действительно кажется о Posix; вот почему я здесь. – thejoshwolfe

+1

@thejoshwolfe: Чтобы избежать условий гонки, вы используете sigprocmask(), чтобы отложить сигналы, установить обработчик, вилку, установить обработчик назад, а затем снова использовать sigprocmask для повторного включения сигналов. (И если любые сигналы поступают между вызовами sigprocmask, они будут доставлены в этот момент.) –

Смежные вопросы