Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 import os
00012 import threading
00013 import subprocess
00014 import signal
00015
00016
00017
00018
00019
00020
00021 class Popen(object):
00022 '''
00023 Use this if you want to attach a postexec function to popen (which
00024 is not supported by popen at all). It also defaults setting and
00025 terminating whole process groups (something we do quite often in ros).
00026 '''
00027 __slots__ = [
00028 'pid',
00029 '_proc',
00030 '_thread',
00031 '_external_preexec_fn',
00032 '_shell',
00033 '_env',
00034 'terminate'
00035 ]
00036
00037 def __init__(self, popen_args, shell=False, preexec_fn=None, postexec_fn=None, env=None):
00038 '''
00039 @param popen_args : list/tuple of usual popen args
00040 @type list/tuple
00041
00042 @param shell : same as the shell argument passed to subprocess.Popen
00043 @type bool
00044
00045 @param preexec_fn : usual popen pre-exec function
00046 @type method with no args
00047
00048 @param postexec_fn : the callback which we support for postexec.
00049 @type method with no args
00050
00051 :param env dict: a customised environment to run the process in.
00052 '''
00053 self.pid = None
00054 self._proc = None
00055 self._shell = shell
00056 self._env = env
00057 self._external_preexec_fn = preexec_fn
00058 self._thread = threading.Thread(target=self._run_in_thread, args=(popen_args, self._preexec_fn, postexec_fn))
00059 self._thread.start()
00060
00061 def send_signal(self, sig):
00062 os.killpg(self._proc.pid, sig)
00063
00064
00065
00066 def _preexec_fn(self):
00067 os.setpgrp()
00068 if self._external_preexec_fn is not None:
00069 self._external_preexec_fn()
00070
00071 def terminate(self):
00072 '''
00073 @raise OSError if the process has already shut down.
00074 '''
00075 return os.killpg(self._proc.pid, signal.SIGTERM)
00076
00077
00078
00079 def _run_in_thread(self, popen_args, preexec_fn, postexec_fn):
00080 '''
00081 Worker function for the thread, creates the subprocess itself.
00082 '''
00083 if preexec_fn is not None:
00084 if self._shell == True:
00085
00086 self._proc = subprocess.Popen(" ".join(popen_args), shell=True, preexec_fn=preexec_fn, env=self._env)
00087 else:
00088
00089 self._proc = subprocess.Popen(popen_args, shell=self._shell, preexec_fn=preexec_fn, env=self._env)
00090 else:
00091 self._proc = subprocess.Popen(popen_args, shell=self._shell, env=self._env)
00092 self.pid = self._proc.pid
00093 self._proc.wait()
00094 if postexec_fn is not None:
00095 postexec_fn()
00096 return