docs: def waitOrTerminate(self, timeoutSeconds, pollInterval=DEFAULT_POLL_INTERVAL, terminateToKillSeconds=SUBPROCESS2_DEFAULT_TERMINATE_TO_KILL_SECONDS):
      '''
          waitOrTerminate - Wait up to a certain number of seconds for the process to end.
  
              If the process is running after the timeout has been exceeded, a SIGTERM will be sent. 
              Optionally, an additional SIGKILL can be sent after some configurable interval. See #terminateToKillSeconds doc below
  
              @param timeoutSeconds <float> - Number of seconds to wait
  
              @param pollInterval <float> (default .05)- Number of seconds between each poll
  
              @param terminateToKillSeconds <float/None> (default 1.5) - If application does not end before #timeoutSeconds , terminate() will be called.
  
                  * If this is set to None, an additional #pollInterval sleep will occur after calling .terminate, to allow the application to cleanup. returnCode will be return of app if finished, or None if did not complete.
                  * If this is set to 0, no terminate signal will be sent, but directly to kill. Because the application cannot trap this, returnCode will be None.
                  * If this is set to > 0, that number of seconds maximum will be given between .terminate and .kill. If the application does not terminate before KILL, returnCode will be None.
  
              Windows Note -- On windows SIGTERM and SIGKILL are the same thing.
  
              @return dict { 'returnCode' : <int or None> , 'actionTaken' : <int mask of SUBPROCESS2_PROCESS_*> }
                  Returns a dict representing results: 
                      "returnCode" matches return of application, or None per #terminateToKillSeconds doc above.
                      "actionTaken" is a mask of the SUBPROCESS2_PROCESS_* variables. If app completed normally, it will be SUBPROCESS2_PROCESS_COMPLETED, otherwise some mask of SUBPROCESS2_PROCESS_TERMINATED and/or SUBPROCESS2_PROCESS_KILLED
      '''
      returnCode = self.waitUpTo(timeoutSeconds, pollInterval)
      actionTaken = SUBPROCESS2_PROCESS_COMPLETED
  
  
      if returnCode is None:
          if terminateToKillSeconds is None:
              self.terminate()
              actionTaken |= SUBPROCESS2_PROCESS_TERMINATED
  
              time.sleep(pollInterval) # Give a chance to cleanup
              returnCode = self.poll()
  
          elif terminateToKillSeconds == 0:
              self.kill()
              actionTaken |= SUBPROCESS2_PROCESS_KILLED
  
              time.sleep(.01)  # Give a chance to happen
              self.poll() # Don't defunct
  
              returnCode = None
          else:
              self.terminate()
              actionTaken |= SUBPROCESS2_PROCESS_TERMINATED
  
              returnCode = self.waitUpTo(terminateToKillSeconds, pollInterval)
              if returnCode is None:
                  actionTaken |= SUBPROCESS2_PROCESS_KILLED
                  self.kill()
                  time.sleep(.01)
                  self.poll() # Don't defunct
  
      return {
          'returnCode' : returnCode,
          'actionTaken' : actionTaken
      }