process.py 2.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
import os
import psutil
import signal
import subprocess
import sys

SLAPRUNNER_PROCESS_LIST = []


class Popen(subprocess.Popen):
  """
Marco Mariani's avatar
Marco Mariani committed
12
  Extension of Popen to launch and kill processes in a clean way
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  """
  def __init__(self, *args, **kwargs):
    """
    Launch process and add object to process list for handler
    """
    self.name = kwargs.pop('name', None)
    kwargs['stdin'] = subprocess.PIPE
    kwargs['stderr'] = subprocess.STDOUT
    kwargs.setdefault('stdout', subprocess.PIPE)
    kwargs.setdefault('close_fds', True)
    subprocess.Popen.__init__(self, *args, **kwargs)
    SLAPRUNNER_PROCESS_LIST.append(self)
    self.stdin.flush()
    self.stdin.close()
    self.stdin = None

  def kill(self, sig=signal.SIGTERM, recursive=False):
    """
Marco Mariani's avatar
Marco Mariani committed
31
    Kill process and all its descendants if recursive
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    """
    if self.poll() is None:
      if recursive:
        childs_pids = pidppid(self.pid)
        for pid in childs_pids:
          killNoFail(pid, sig)
      killNoFail(self.pid, sig)
      if self.poll() is not None:
        SLAPRUNNER_PROCESS_LIST.remove(self)

  def __del__(self):
    """
    Del function, try to kill process group
    and process if its group does not exist
    """
    for pid in (-self.pid, self.pid):
      try:
        os.kill(-self.pid, 15)
      except OSError:
        pass
    subprocess.Popen.__del__(self)


def pidppid(pid, recursive=True):
  """
  Return a list of all children of pid
  """
  return [p.pid for p in psutil.Process(pid).get_children(recursive=recursive)]


def killNoFail(pid, sig):
  """
  function to kill without failing. Return True if kill do not fail
  """
  try:
    os.kill(pid, sig)
    return True
  except OSError:
    return False


def isRunning(name):
  """
  Return True if a process with this name is running
  """
  for process in SLAPRUNNER_PROCESS_LIST:
    if process.name == name:
      if process.poll() is None:
        return True
  return False


def killRunningProcess(name, recursive=False):
  """
Marco Mariani's avatar
Marco Mariani committed
86
  Kill all processes with a given name
87 88 89 90 91 92 93 94
  """
  for process in SLAPRUNNER_PROCESS_LIST:
    if process.name == name:
      process.kill(recursive=recursive)


def handler(sig, frame):
  """
Marco Mariani's avatar
Marco Mariani committed
95
  Signal handler to kill all processes
96 97 98 99 100 101 102 103 104 105 106
  """
  pid = os.getpid()
  os.kill(-pid, sig)
  sys.exit()


def setHandler(sig_list=None):
  if sig_list is None:
    sig_list = [signal.SIGTERM]
  for sig in sig_list:
    signal.signal(sig, handler)