tests/killdaemons.py
changeset 1881 3945f343f084
parent 1880 4907f2aed924
child 1882 b6f934ed3570
equal deleted inserted replaced
1880:4907f2aed924 1881:3945f343f084
     1 #!/usr/bin/env python
       
     2 
       
     3 import os, sys, time, errno, signal
       
     4 
       
     5 if os.name =='nt':
       
     6     import ctypes
       
     7 
       
     8     def _check(ret, expectederr=None):
       
     9         if ret == 0:
       
    10             winerrno = ctypes.GetLastError()
       
    11             if winerrno == expectederr:
       
    12                 return True
       
    13             raise ctypes.WinError(winerrno)
       
    14 
       
    15     def kill(pid, logfn, tryhard=True):
       
    16         logfn('# Killing daemon process %d' % pid)
       
    17         PROCESS_TERMINATE = 1
       
    18         PROCESS_QUERY_INFORMATION = 0x400
       
    19         SYNCHRONIZE = 0x00100000
       
    20         WAIT_OBJECT_0 = 0
       
    21         WAIT_TIMEOUT = 258
       
    22         handle = ctypes.windll.kernel32.OpenProcess(
       
    23                 PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
       
    24                 False, pid)
       
    25         if handle == 0:
       
    26             _check(0, 87) # err 87 when process not found
       
    27             return # process not found, already finished
       
    28         try:
       
    29             r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
       
    30             if r == WAIT_OBJECT_0:
       
    31                 pass # terminated, but process handle still available
       
    32             elif r == WAIT_TIMEOUT:
       
    33                 _check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
       
    34             else:
       
    35                 _check(r)
       
    36 
       
    37             # TODO?: forcefully kill when timeout
       
    38             #        and ?shorter waiting time? when tryhard==True
       
    39             r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
       
    40                                                        # timeout = 100 ms
       
    41             if r == WAIT_OBJECT_0:
       
    42                 pass # process is terminated
       
    43             elif r == WAIT_TIMEOUT:
       
    44                 logfn('# Daemon process %d is stuck')
       
    45             else:
       
    46                 _check(r) # any error
       
    47         except: #re-raises
       
    48             ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
       
    49             raise
       
    50         _check(ctypes.windll.kernel32.CloseHandle(handle))
       
    51 
       
    52 else:
       
    53     def kill(pid, logfn, tryhard=True):
       
    54         try:
       
    55             os.kill(pid, 0)
       
    56             logfn('# Killing daemon process %d' % pid)
       
    57             os.kill(pid, signal.SIGTERM)
       
    58             if tryhard:
       
    59                 for i in range(10):
       
    60                     time.sleep(0.05)
       
    61                     os.kill(pid, 0)
       
    62             else:
       
    63                 time.sleep(0.1)
       
    64                 os.kill(pid, 0)
       
    65             logfn('# Daemon process %d is stuck - really killing it' % pid)
       
    66             os.kill(pid, signal.SIGKILL)
       
    67         except OSError as err:
       
    68             if err.errno != errno.ESRCH:
       
    69                 raise
       
    70 
       
    71 def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
       
    72     if not logfn:
       
    73         logfn = lambda s: s
       
    74     # Kill off any leftover daemon processes
       
    75     try:
       
    76         fp = open(pidfile)
       
    77         for line in fp:
       
    78             try:
       
    79                 pid = int(line)
       
    80             except ValueError:
       
    81                 continue
       
    82             kill(pid, logfn, tryhard)
       
    83         fp.close()
       
    84         if remove:
       
    85             os.unlink(pidfile)
       
    86     except IOError:
       
    87         pass
       
    88 
       
    89 if __name__ == '__main__':
       
    90     path, = sys.argv[1:]
       
    91     killdaemons(path)