github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/rpc/pid.py (about)

     1  #!/usr/bin/env python
     2  
     3  """ An executable which proxies for a subprocess; upon a signal, it sends that
     4  signal to the process identified by a pidfile. """
     5  
     6  import os
     7  import sys
     8  import signal
     9  import time
    10  
    11  
    12  class PidProxy:
    13      pid = None
    14      def __init__(self, args):
    15          self.setsignals()
    16          self.reaped_parent = False
    17  
    18          try:
    19              self.pidfile, cmdargs = args[1], args[2:]
    20              self.command = os.path.abspath(cmdargs[0])
    21              self.cmdargs = cmdargs
    22          except (ValueError, IndexError):
    23              self.usage()
    24              sys.exit(1)
    25  
    26      def getpidfromfile(self):
    27          try:
    28              with open(self.pidfile, 'r') as f:
    29                  return int(f.read().strip())
    30          except:
    31              return None
    32  
    33      def go(self):
    34          self.pid = os.spawnv(os.P_NOWAIT, self.command, self.cmdargs)
    35          while 1:
    36              time.sleep(5)
    37              try:
    38                  self.pid = self.getpidfromfile()
    39                  if self.pid is None:
    40                      break
    41                  pid, sts = os.waitpid(self.pid, os.WNOHANG)
    42              except OSError:
    43                  pid, sts = None, None
    44              if pid:
    45                  break
    46  
    47      def usage(self):
    48          print("pidproxy.py <pidfile name> <command> [<cmdarg1> ...]")
    49  
    50      def setsignals(self):
    51          signal.signal(signal.SIGTERM, self.passtochild)
    52          signal.signal(signal.SIGHUP, self.passtochild)
    53          signal.signal(signal.SIGINT, self.passtochild)
    54          signal.signal(signal.SIGUSR1, self.passtochild)
    55          signal.signal(signal.SIGUSR2, self.passtochild)
    56          signal.signal(signal.SIGQUIT, self.passtochild)
    57          signal.signal(signal.SIGCHLD, self.reap)
    58  
    59      def reap(self, sig, frame):
    60          if not self.reaped_parent:
    61              os.waitpid(-1, 0)
    62              self.reaped_parent = True
    63              return
    64          try:
    65              pid = self.getpidfromfile()
    66              if pid is None:
    67                  pid = self.pid
    68              _, _ = os.waitpid(pid, 0)
    69              sys.exit(0)
    70          except:
    71              pass
    72  
    73      def passtochild(self, sig, frame):
    74          pid = self.getpidfromfile()
    75          if pid is None:
    76              pid = self.pid
    77          os.kill(pid, sig)
    78          if sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]:
    79              sys.exit(0)
    80  
    81  
    82  def main():
    83      pp = PidProxy(sys.argv)
    84      pp.go()
    85  
    86  if __name__ == '__main__':
    87      main()