sherlock
sherlock

Reputation: 2807

Why is Python signal handler not getting triggered?

In the code snippet below, I registered the signal handler with a call to signal.signal. However, though the process is killed after the timeout, the print or system statements inside the handler are not being executed. What am I doing wrong? I am running Python 2.7.15rc1 on Ubuntu 18.04, 64 bit.

import signal
import time
import os
import multiprocessing as mp

def handler(signal, frame):
    print "Alarmed"
    os.system('echo Alarmed >> /tmp/log_alarm')

def launch():
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(5)
    print "Process launched"
    os.execv('/bin/cat', ['cat'])
    print "You should not see this"

p = mp.Process(target=launch)
p.start()
print "Process started"
p.join()

Upvotes: 2

Views: 2332

Answers (1)

Ondrej K.
Ondrej K.

Reputation: 9664

You are at that point out of Python territory. os.execv() ultimately caused execve(2) syscall to be made and as its man page states:

All process attributes are preserved during an execve(), except the following:

  • The dispositions of any signals that are being caught are reset to the default (signal(7)).

...

Which does make sense, you shouldn't really want to run some new code while having old handlers registered for it (and no idea how that could even work since handlers would also be replaced).


If you implemented cat-like behavior in python and did not execve a new process, it would have (more or less) worked the way you expected:

import signal
import time
import os
import sys
import multiprocessing as mp

def handler(signal, frame):
    print "Alarmed"
    os.system('echo Alarmed >> /tmp/log_alarm')
    sys.exit(0)

def launch():
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(5)
    print "Process launched"
    stdin = os.fdopen(0)
    stdout = os.fdopen(1, 'w')
    line = stdin.readline()
    while line:
        stdout.write(line)
        line = stdin.readline()
    print "You may end here if EOF was reached before being alarmed."

p = mp.Process(target=launch)
p.start()
print "Process started"
p.join()

Note: I've just hard coded handling of stdin/stdout in the child process. And since you've mentioned python 2.7 I've avoided using for line in stdin:.

Upvotes: 3

Related Questions