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