Reputation: 7271
I am running multiple processes using subprocess.Popen and when I detect a change in any of some of a group of files, I want to send a signal to one of these process. I have defined a signal handler in the process but it doesnt seem that it is being sent any signal. some help would be appreciated. The function that does the sending of the signal and the signal handler are shown below.
def start_up():
p, i = None, None
while 1:
subprocess.call(['clear'])
logging.info('starting overlay on host %s' % socket.gethostname())
p = subprocess.Popen([sys.executable, 'sdp_proc.py'])
i = subprocess.Popen([sys.executable, 'kernel.py', sys.argv[1],
sys.argv[2]])
if file_modified():
p.terminate()
i.send_signal(signal.SIGINT)
time.sleep(1)
The signal handler is shown below:
def signal_handler(signum, frame):
with open('log.txt', 'w') as f:
f.write(' so what mate, received signal with signal number %s' % signum)
signal.signal(signal.SIGINT, signal_handler)
Upvotes: 4
Views: 3699
Reputation: 8055
According to the official documentation in both Unix
and NT
, you need to use process groups to receive signals if the shell=True
is used.
So, I decided to wrap the built-in Popen
function to achieve this behaviour.
import subprocess as sp
import os
def Popen(command, env=None, **kw):
if os.name == 'nt':
# On Windows, the specified env must include a valid SystemRoot
# Use a current value
if env is None:
env = {}
env['SystemRoot'] = os.environ['SystemRoot']
kw['creationflags'] = sp.CREATE_NEW_PROCESS_GROUP
else:
kw['preexec_fn'] = os.setpgrp
return sp.Popen(command, env=env, **kw)
Cross-platform kill function:
if os.name == 'nt':
# On Windows, os module can't kill processes by group
# Kill all children indiscriminately instead
def killpg_by_pid(pid, s):
# Ignoring s due the lack of support in windows.j
sp.call(['taskkill', '/T', '/F', '/PID', str(pid)])
else:
def killpg_by_pid(pid, s):
os.killpg(os.getpgid(pid), s)
Usage:
tested in Linux and Windows.
import signal
process = Popen(
command,
stdout=sp.PIPE,
stderr=sp.PIPE,
shell=True,
**kw,
)
# Kill
killpg_by_pid(process.pid, signal.SIGTERM)
For a complete example please take a look at: bddcli.
Upvotes: 0
Reputation: 9161
I'd guess that the SIGINT is being sent to the subprocess before it even has a chance to load up all of Python, so before it installs the SIGINT handler, meaning it will die right away.
You probably want to watch the subprocess for some successful-load condition to be met (perhaps just sending a byte on a pipe) before sending it any SIGINT signals that you expect to be handled by your own handler code.
Upvotes: 2