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