|
1 /* |
|
2 * Helper program for killing lingering python[_d].exe processes before |
|
3 * building, thus attempting to avoid build failures due to files being |
|
4 * locked. |
|
5 */ |
|
6 |
|
7 #include <windows.h> |
|
8 #include <wchar.h> |
|
9 #include <tlhelp32.h> |
|
10 #include <stdio.h> |
|
11 |
|
12 #pragma comment(lib, "psapi") |
|
13 |
|
14 #ifdef _DEBUG |
|
15 #define PYTHON_EXE (L"python_d.exe") |
|
16 #define PYTHON_EXE_LEN (12) |
|
17 #define KILL_PYTHON_EXE (L"kill_python_d.exe") |
|
18 #define KILL_PYTHON_EXE_LEN (17) |
|
19 #else |
|
20 #define PYTHON_EXE (L"python.exe") |
|
21 #define PYTHON_EXE_LEN (10) |
|
22 #define KILL_PYTHON_EXE (L"kill_python.exe") |
|
23 #define KILL_PYTHON_EXE_LEN (15) |
|
24 #endif |
|
25 |
|
26 int |
|
27 main(int argc, char **argv) |
|
28 { |
|
29 HANDLE hp, hsp, hsm; /* process, snapshot processes, snapshot modules */ |
|
30 DWORD dac, our_pid; |
|
31 size_t len; |
|
32 wchar_t path[MAX_PATH+1]; |
|
33 |
|
34 MODULEENTRY32W me; |
|
35 PROCESSENTRY32W pe; |
|
36 |
|
37 me.dwSize = sizeof(MODULEENTRY32W); |
|
38 pe.dwSize = sizeof(PROCESSENTRY32W); |
|
39 |
|
40 memset(path, 0, MAX_PATH+1); |
|
41 |
|
42 our_pid = GetCurrentProcessId(); |
|
43 |
|
44 hsm = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, our_pid); |
|
45 if (hsm == INVALID_HANDLE_VALUE) { |
|
46 printf("CreateToolhelp32Snapshot[1] failed: %d\n", GetLastError()); |
|
47 return 1; |
|
48 } |
|
49 |
|
50 if (!Module32FirstW(hsm, &me)) { |
|
51 printf("Module32FirstW[1] failed: %d\n", GetLastError()); |
|
52 CloseHandle(hsm); |
|
53 return 1; |
|
54 } |
|
55 |
|
56 /* |
|
57 * Enumerate over the modules for the current process in order to find |
|
58 * kill_process[_d].exe, then take a note of the directory it lives in. |
|
59 */ |
|
60 do { |
|
61 if (_wcsnicmp(me.szModule, KILL_PYTHON_EXE, KILL_PYTHON_EXE_LEN)) |
|
62 continue; |
|
63 |
|
64 len = wcsnlen_s(me.szExePath, MAX_PATH) - KILL_PYTHON_EXE_LEN; |
|
65 wcsncpy_s(path, MAX_PATH+1, me.szExePath, len); |
|
66 |
|
67 break; |
|
68 |
|
69 } while (Module32NextW(hsm, &me)); |
|
70 |
|
71 CloseHandle(hsm); |
|
72 |
|
73 if (path == NULL) { |
|
74 printf("failed to discern directory of running process\n"); |
|
75 return 1; |
|
76 } |
|
77 |
|
78 /* |
|
79 * Take a snapshot of system processes. Enumerate over the snapshot, |
|
80 * looking for python processes. When we find one, verify it lives |
|
81 * in the same directory we live in. If it does, kill it. If we're |
|
82 * unable to kill it, treat this as a fatal error and return 1. |
|
83 * |
|
84 * The rationale behind this is that we're called at the start of the |
|
85 * build process on the basis that we'll take care of killing any |
|
86 * running instances, such that the build won't encounter permission |
|
87 * denied errors during linking. If we can't kill one of the processes, |
|
88 * we can't provide this assurance, and the build shouldn't start. |
|
89 */ |
|
90 |
|
91 hsp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
|
92 if (hsp == INVALID_HANDLE_VALUE) { |
|
93 printf("CreateToolhelp32Snapshot[2] failed: %d\n", GetLastError()); |
|
94 return 1; |
|
95 } |
|
96 |
|
97 if (!Process32FirstW(hsp, &pe)) { |
|
98 printf("Process32FirstW failed: %d\n", GetLastError()); |
|
99 CloseHandle(hsp); |
|
100 return 1; |
|
101 } |
|
102 |
|
103 dac = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE; |
|
104 do { |
|
105 |
|
106 /* |
|
107 * XXX TODO: if we really wanted to be fancy, we could check the |
|
108 * modules for all processes (not just the python[_d].exe ones) |
|
109 * and see if any of our DLLs are loaded (i.e. python30[_d].dll), |
|
110 * as that would also inhibit our ability to rebuild the solution. |
|
111 * Not worth loosing sleep over though; for now, a simple check |
|
112 * for just the python executable should be sufficient. |
|
113 */ |
|
114 |
|
115 if (_wcsnicmp(pe.szExeFile, PYTHON_EXE, PYTHON_EXE_LEN)) |
|
116 /* This isn't a python process. */ |
|
117 continue; |
|
118 |
|
119 /* It's a python process, so figure out which directory it's in... */ |
|
120 hsm = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe.th32ProcessID); |
|
121 if (hsm == INVALID_HANDLE_VALUE) |
|
122 /* |
|
123 * If our module snapshot fails (which will happen if we don't own |
|
124 * the process), just ignore it and continue. (It seems different |
|
125 * versions of Windows return different values for GetLastError() |
|
126 * in this situation; it's easier to just ignore it and move on vs. |
|
127 * stopping the build for what could be a false positive.) |
|
128 */ |
|
129 continue; |
|
130 |
|
131 if (!Module32FirstW(hsm, &me)) { |
|
132 printf("Module32FirstW[2] failed: %d\n", GetLastError()); |
|
133 CloseHandle(hsp); |
|
134 CloseHandle(hsm); |
|
135 return 1; |
|
136 } |
|
137 |
|
138 do { |
|
139 if (_wcsnicmp(me.szModule, PYTHON_EXE, PYTHON_EXE_LEN)) |
|
140 /* Wrong module, we're looking for python[_d].exe... */ |
|
141 continue; |
|
142 |
|
143 if (_wcsnicmp(path, me.szExePath, len)) |
|
144 /* Process doesn't live in our directory. */ |
|
145 break; |
|
146 |
|
147 /* Python process residing in the right directory, kill it! */ |
|
148 hp = OpenProcess(dac, FALSE, pe.th32ProcessID); |
|
149 if (!hp) { |
|
150 printf("OpenProcess failed: %d\n", GetLastError()); |
|
151 CloseHandle(hsp); |
|
152 CloseHandle(hsm); |
|
153 return 1; |
|
154 } |
|
155 |
|
156 if (!TerminateProcess(hp, 1)) { |
|
157 printf("TerminateProcess failed: %d\n", GetLastError()); |
|
158 CloseHandle(hsp); |
|
159 CloseHandle(hsm); |
|
160 CloseHandle(hp); |
|
161 return 1; |
|
162 } |
|
163 |
|
164 CloseHandle(hp); |
|
165 break; |
|
166 |
|
167 } while (Module32NextW(hsm, &me)); |
|
168 |
|
169 CloseHandle(hsm); |
|
170 |
|
171 } while (Process32NextW(hsp, &pe)); |
|
172 |
|
173 CloseHandle(hsp); |
|
174 |
|
175 return 0; |
|
176 } |
|
177 |
|
178 /* vi: set ts=8 sw=4 sts=4 expandtab */ |