popen.py
Go to the documentation of this file.
00001 #
00002 # License: BSD
00003 #   https://raw.github.com/robotics-in-concert/rocon_tools/license/LICENSE
00004 #
00005 
00006 ##############################################################################
00007 # Imports
00008 ##############################################################################
00009 
00010 # system
00011 import os
00012 import threading
00013 import subprocess
00014 import signal
00015 
00016 ##############################################################################
00017 # Subprocess
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         # This would be the normal way if not defaulting settings for process groups
00064         #self._proc.send_signal(sig)
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         # if we were not setting process groups
00077         #return self._proc.terminate() if self._proc is not None else None
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                 #print("rocon_python_utils.os.Popen: %s" % " ".join(popen_args))
00086                 self._proc = subprocess.Popen(" ".join(popen_args), shell=True, preexec_fn=preexec_fn, env=self._env)
00087             else:
00088                 #print("rocon_python_utils.os..Popen: %s" % popen_args)
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


rocon_python_utils
Author(s): Daniel Stonier
autogenerated on Fri May 2 2014 10:35:39