def __init__(self,
              cmdArgs = None,
              do = nub,
              final = nub,
              frequency = 1,
              pipeOut = False,
              pipeErr = False):
    super(SubProcMonitor, self).__init__()
    self.cmdArgs = cmdArgs
    self.frequency = frequency
    self.do = do
    self.final = final
    self.pipeOut = pipeOut
    self.pipeErr = pipeErr
    # start a thread to check the subprocess repeatedly
    def update(autoproc):
       try:
          # while the subprocess is running
          code = self.subproc.poll()
          if code == None:
             self.do(self)
          # when the subprocess terminates, the monitor terminates
          else:
             autoproc.kill()
             if code == 0:
                self.setSuccess()
             else:
                errMsg = "SubProcMonitor: subprocess exits with %s.\n" % str(self.subproc.poll())
                if self.pipeOut:
                   errMsg += "stdout:\n%s\n" % self.subproc.stdout.read()
                if self.pipeErr:
                   errMsg += "stderr:\n%s\n" % self.subproc.stderr.read()
                raise Exception(errMsg)
       except Exception as e:
          if self.subproc.poll() == None: self.kill()
          self.setFailure(e)
          autoproc.kill()
          raise e
          
    self.autoproc = AutoProcess(update=update, final=lambda proc:self.final(self), frequency=self.frequency)
class SubProcMonitor(State):

   def __init__(self,
                cmdArgs = None,
                do = nub,
                final = nub,
                frequency = 1,
                pipeOut = False,
                pipeErr = False):
      super(SubProcMonitor, self).__init__()
      self.cmdArgs = cmdArgs
      self.frequency = frequency
      self.do = do
      self.final = final
      self.pipeOut = pipeOut
      self.pipeErr = pipeErr
      # start a thread to check the subprocess repeatedly
      def update(autoproc):
         try:
            # while the subprocess is running
            code = self.subproc.poll()
            if code == None:
               self.do(self)
            # when the subprocess terminates, the monitor terminates
            else:
               autoproc.kill()
               if code == 0:
                  self.setSuccess()
               else:
                  errMsg = "SubProcMonitor: subprocess exits with %s.\n" % str(self.subproc.poll())
                  if self.pipeOut:
                     errMsg += "stdout:\n%s\n" % self.subproc.stdout.read()
                  if self.pipeErr:
                     errMsg += "stderr:\n%s\n" % self.subproc.stderr.read()
                  raise Exception(errMsg)
         except Exception as e:
            if self.subproc.poll() == None: self.kill()
            self.setFailure(e)
            autoproc.kill()
            raise e
            
      self.autoproc = AutoProcess(update=update, final=lambda proc:self.final(self), frequency=self.frequency)

   def start(self, threadName = "monitor"):
      assert self.isAwait(), \
         "SubProcMonitor: Attempted to use a process twice, please allocate a new ProcMonitor."
      self.threadName = threadName
      if OS.name == 'posix':
         creationflags = 0
      elif OS.name == 'nt':
         creationflags = CREATE_NEW_PROCESS_GROUP
      self.subproc = Popen(self.cmdArgs, 
                           stdout=PIPE if self.pipeOut else None, 
                           stderr=PIPE if self.pipeErr else None, 
                           universal_newlines=True,
                           creationflags=creationflags)
      assert self.subproc.pid, \
         "SubProcMonitor: Subprocess could not start."
      self.stdout = self.subproc.stdout
      self.stderr = self.subproc.stderr
      self.setRunning()
      self.autoproc.start(threadName)

   def kill(self):
      if not self.isRunning():
         warn("SubProcMonitor.kill: SubProcMonitor is "+self.show()+".")
      else:
         self.setFailure("killed")
         if OS.name == 'nt':
            sig = CTRL_BREAK_EVENT 
         elif OS.name == 'posix':
            sig = SIGINT
         self.subproc.send_signal(sig)
         self.subproc.wait()
         
   def join(self):
      if self.isRunning():
         self.subproc.wait()
         if self.autoproc.isRunning(): self.autoproc.join()
         assert not self.subproc.poll() == None, \
            "SubProcMonitor: subprocess still running."
         assert not self.autoproc.isRunning(), \
            "SubProcMonitor: autoproc still running."
      else:
         warn("SubProcMonitor: attempted to join a process that's not running.")