##// END OF EJS Templates
killdaemons: close pid file before killing processes...
Matt Harbison -
r32677:f840b262 default
parent child Browse files
Show More
@@ -1,104 +1,106 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from __future__ import absolute_import
3 from __future__ import absolute_import
4 import errno
4 import errno
5 import os
5 import os
6 import signal
6 import signal
7 import sys
7 import sys
8 import time
8 import time
9
9
10 if os.name =='nt':
10 if os.name =='nt':
11 import ctypes
11 import ctypes
12
12
13 def _check(ret, expectederr=None):
13 def _check(ret, expectederr=None):
14 if ret == 0:
14 if ret == 0:
15 winerrno = ctypes.GetLastError()
15 winerrno = ctypes.GetLastError()
16 if winerrno == expectederr:
16 if winerrno == expectederr:
17 return True
17 return True
18 raise ctypes.WinError(winerrno)
18 raise ctypes.WinError(winerrno)
19
19
20 def kill(pid, logfn, tryhard=True):
20 def kill(pid, logfn, tryhard=True):
21 logfn('# Killing daemon process %d' % pid)
21 logfn('# Killing daemon process %d' % pid)
22 PROCESS_TERMINATE = 1
22 PROCESS_TERMINATE = 1
23 PROCESS_QUERY_INFORMATION = 0x400
23 PROCESS_QUERY_INFORMATION = 0x400
24 SYNCHRONIZE = 0x00100000
24 SYNCHRONIZE = 0x00100000
25 WAIT_OBJECT_0 = 0
25 WAIT_OBJECT_0 = 0
26 WAIT_TIMEOUT = 258
26 WAIT_TIMEOUT = 258
27 handle = ctypes.windll.kernel32.OpenProcess(
27 handle = ctypes.windll.kernel32.OpenProcess(
28 PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
28 PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
29 False, pid)
29 False, pid)
30 if handle == 0:
30 if handle == 0:
31 _check(0, 87) # err 87 when process not found
31 _check(0, 87) # err 87 when process not found
32 return # process not found, already finished
32 return # process not found, already finished
33 try:
33 try:
34 r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
34 r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
35 if r == WAIT_OBJECT_0:
35 if r == WAIT_OBJECT_0:
36 pass # terminated, but process handle still available
36 pass # terminated, but process handle still available
37 elif r == WAIT_TIMEOUT:
37 elif r == WAIT_TIMEOUT:
38 _check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
38 _check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
39 else:
39 else:
40 _check(r)
40 _check(r)
41
41
42 # TODO?: forcefully kill when timeout
42 # TODO?: forcefully kill when timeout
43 # and ?shorter waiting time? when tryhard==True
43 # and ?shorter waiting time? when tryhard==True
44 r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
44 r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
45 # timeout = 100 ms
45 # timeout = 100 ms
46 if r == WAIT_OBJECT_0:
46 if r == WAIT_OBJECT_0:
47 pass # process is terminated
47 pass # process is terminated
48 elif r == WAIT_TIMEOUT:
48 elif r == WAIT_TIMEOUT:
49 logfn('# Daemon process %d is stuck')
49 logfn('# Daemon process %d is stuck')
50 else:
50 else:
51 _check(r) # any error
51 _check(r) # any error
52 except: #re-raises
52 except: #re-raises
53 ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
53 ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
54 raise
54 raise
55 _check(ctypes.windll.kernel32.CloseHandle(handle))
55 _check(ctypes.windll.kernel32.CloseHandle(handle))
56
56
57 else:
57 else:
58 def kill(pid, logfn, tryhard=True):
58 def kill(pid, logfn, tryhard=True):
59 try:
59 try:
60 os.kill(pid, 0)
60 os.kill(pid, 0)
61 logfn('# Killing daemon process %d' % pid)
61 logfn('# Killing daemon process %d' % pid)
62 os.kill(pid, signal.SIGTERM)
62 os.kill(pid, signal.SIGTERM)
63 if tryhard:
63 if tryhard:
64 for i in range(10):
64 for i in range(10):
65 time.sleep(0.05)
65 time.sleep(0.05)
66 os.kill(pid, 0)
66 os.kill(pid, 0)
67 else:
67 else:
68 time.sleep(0.1)
68 time.sleep(0.1)
69 os.kill(pid, 0)
69 os.kill(pid, 0)
70 logfn('# Daemon process %d is stuck - really killing it' % pid)
70 logfn('# Daemon process %d is stuck - really killing it' % pid)
71 os.kill(pid, signal.SIGKILL)
71 os.kill(pid, signal.SIGKILL)
72 except OSError as err:
72 except OSError as err:
73 if err.errno != errno.ESRCH:
73 if err.errno != errno.ESRCH:
74 raise
74 raise
75
75
76 def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
76 def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
77 if not logfn:
77 if not logfn:
78 logfn = lambda s: s
78 logfn = lambda s: s
79 # Kill off any leftover daemon processes
79 # Kill off any leftover daemon processes
80 try:
80 try:
81 fp = open(pidfile)
81 pids = []
82 with open(pidfile) as fp:
82 for line in fp:
83 for line in fp:
83 try:
84 try:
84 pid = int(line)
85 pid = int(line)
85 if pid <= 0:
86 if pid <= 0:
86 raise ValueError
87 raise ValueError
87 except ValueError:
88 except ValueError:
88 logfn('# Not killing daemon process %s - invalid pid'
89 logfn('# Not killing daemon process %s - invalid pid'
89 % line.rstrip())
90 % line.rstrip())
90 continue
91 continue
92 pids.append(pid)
93 for pid in pids:
91 kill(pid, logfn, tryhard)
94 kill(pid, logfn, tryhard)
92 fp.close()
93 if remove:
95 if remove:
94 os.unlink(pidfile)
96 os.unlink(pidfile)
95 except IOError:
97 except IOError:
96 pass
98 pass
97
99
98 if __name__ == '__main__':
100 if __name__ == '__main__':
99 if len(sys.argv) > 1:
101 if len(sys.argv) > 1:
100 path, = sys.argv[1:]
102 path, = sys.argv[1:]
101 else:
103 else:
102 path = os.environ["DAEMON_PIDS"]
104 path = os.environ["DAEMON_PIDS"]
103
105
104 killdaemons(path)
106 killdaemons(path)
General Comments 0
You need to be logged in to leave comments. Login now