2727
2828
2929#define THREAD_TIMEOUT 100 // ms
30- // Global object shared between the 2 threads.
31- PUNICODE_STRING globalFileName = NULL ;
30+ #define STATUS_UNSUCCESSFUL ((DWORD)0xC0000001L)
31+
32+ typedef struct
33+ {
34+ NTSTATUS status ;
35+ HANDLE hFile ;
36+ PUNICODE_STRING FileName ;
37+ ULONG Length ;
38+ } psutil_query_thread ;
3239
3340
3441static int
@@ -80,129 +87,105 @@ psutil_enum_handles(PSYSTEM_HANDLE_INFORMATION_EX *handles) {
8087 return 0 ;
8188}
8289
83-
84- static int
90+ static DWORD
8591psutil_get_filename (LPVOID lpvParam ) {
86- HANDLE hFile = * ((HANDLE * )lpvParam );
87- NTSTATUS status ;
88- ULONG bufferSize ;
89- ULONG attempts = 8 ;
90-
91- bufferSize = 0x200 ;
92- globalFileName = MALLOC_ZERO (bufferSize );
93- if (globalFileName == NULL ) {
94- PyErr_NoMemory ();
95- goto error ;
96- }
92+ psutil_query_thread * context = lpvParam ;
93+
94+ context -> status = NtQueryObject (
95+ context -> hFile ,
96+ ObjectNameInformation ,
97+ context -> FileName ,
98+ context -> Length ,
99+ & context -> Length );
100+ return 0 ;
101+ }
97102
98103
99- // Note: also this is supposed to hang, hence why we do it in here.
100- if (GetFileType (hFile ) != FILE_TYPE_DISK ) {
101- SetLastError (0 );
102- globalFileName -> Length = 0 ;
103- return 0 ;
104+ static PUNICODE_STRING
105+ psutil_threaded_get_filename (HANDLE hFile ) {
106+ DWORD dwWait ;
107+ HANDLE hThread ;
108+ DWORD result = 0 ;
109+ ULONG attempts = 8 ;
110+ psutil_query_thread threadContext = {
111+ .status = STATUS_UNSUCCESSFUL ,
112+ .hFile = hFile ,
113+ .FileName = NULL ,
114+ .Length = 0x200 ,
115+ };
116+
117+ threadContext .FileName = MALLOC_ZERO (threadContext .Length );
118+ if (threadContext .FileName == NULL ) {
119+ PyErr_NoMemory ();
120+ return NULL ;
104121 }
105122
106123 // A loop is needed because the I/O subsystem likes to give us the
107124 // wrong return lengths...
108125 do {
109- status = NtQueryObject (
110- hFile ,
111- ObjectNameInformation ,
112- globalFileName ,
113- bufferSize ,
114- & bufferSize
115- );
116- if (status == STATUS_BUFFER_OVERFLOW ||
117- status == STATUS_INFO_LENGTH_MISMATCH ||
118- status == STATUS_BUFFER_TOO_SMALL )
126+ hThread = CreateThread (
127+ NULL , 0 , (LPTHREAD_START_ROUTINE )psutil_get_filename ,
128+ & threadContext , 0 , NULL );
129+ if (hThread == NULL ) {
130+ PyErr_SetFromOSErrnoWithSyscall ("CreateThread" );
131+ FREE (threadContext .FileName );
132+ return NULL ;
133+ }
134+
135+ // Wait for the worker thread to finish.
136+ dwWait = WaitForSingleObject (hThread , THREAD_TIMEOUT );
137+
138+ // If the thread hangs, kill it and cleanup.
139+ if (dwWait == WAIT_TIMEOUT ) {
140+ psutil_debug (
141+ "get handle name thread timed out after %i ms" , THREAD_TIMEOUT );
142+ if (TerminateThread (hThread , 0 ) == 0 ) {
143+ PyErr_SetFromOSErrnoWithSyscall ("TerminateThread" );
144+ result = 1 ;
145+ }
146+ } else if (dwWait == WAIT_FAILED ) {
147+ psutil_debug ("WaitForSingleObject -> WAIT_FAILED" );
148+ result = 1 ;
149+ if (TerminateThread (hThread , 0 ) == 0 ) {
150+ PyErr_SetFromOSErrnoWithSyscall (
151+ "WaitForSingleObject -> WAIT_FAILED -> TerminateThread" );
152+ } else {
153+ PyErr_SetFromOSErrnoWithSyscall ("WaitForSingleObject" );
154+ }
155+ } else if (GetExitCodeThread (hThread , & result ) == 0 ) {
156+ result = 1 ;
157+ PyErr_SetFromOSErrnoWithSyscall ("GetExitCodeThread" );
158+ } else if (threadContext .status == STATUS_BUFFER_OVERFLOW ||
159+ threadContext .status == STATUS_INFO_LENGTH_MISMATCH ||
160+ threadContext .status == STATUS_BUFFER_TOO_SMALL )
119161 {
120- FREE (globalFileName );
121- globalFileName = MALLOC_ZERO (bufferSize );
122- if (globalFileName == NULL ) {
162+ FREE (threadContext . FileName );
163+ threadContext . FileName = MALLOC_ZERO (threadContext . Length );
164+ if (threadContext . FileName == NULL ) {
123165 PyErr_NoMemory ();
124- goto error ;
166+ CloseHandle (hThread );
167+ return NULL ;
125168 }
126- }
127- else {
169+ } else {
170+ CloseHandle ( hThread );
128171 break ;
129172 }
130- } while (-- attempts );
131-
132- if (! NT_SUCCESS (status )) {
133- psutil_SetFromNTStatusErr (status , "NtQuerySystemInformation" );
134- FREE (globalFileName );
135- globalFileName = NULL ;
136- return 1 ;
137- }
138-
139- return 0 ;
140-
141- error :
142- if (globalFileName != NULL ) {
143- FREE (globalFileName );
144- globalFileName = NULL ;
145- }
146- return 1 ;
147- }
148-
149-
150- static DWORD
151- psutil_threaded_get_filename (HANDLE hFile ) {
152- DWORD dwWait ;
153- HANDLE hThread ;
154- DWORD threadRetValue ;
155-
156- hThread = CreateThread (
157- NULL , 0 , (LPTHREAD_START_ROUTINE )psutil_get_filename , & hFile , 0 , NULL );
158- if (hThread == NULL ) {
159- PyErr_SetFromOSErrnoWithSyscall ("CreateThread" );
160- return 1 ;
161- }
173+ CloseHandle (hThread );
162174
163- // Wait for the worker thread to finish.
164- dwWait = WaitForSingleObject (hThread , THREAD_TIMEOUT );
175+ } while (-- attempts && !result );
165176
166- // If the thread hangs, kill it and cleanup.
167- if (dwWait == WAIT_TIMEOUT ) {
168- psutil_debug (
169- "get handle name thread timed out after %i ms" , THREAD_TIMEOUT );
170- if (TerminateThread (hThread , 0 ) == 0 ) {
171- PyErr_SetFromOSErrnoWithSyscall ("TerminateThread" );
172- CloseHandle (hThread );
173- return 1 ;
174- }
175- CloseHandle (hThread );
176- return 0 ;
177+ if (result ) {
178+ FREE (threadContext .FileName );
179+ return NULL ;
177180 }
178181
179- if (dwWait == WAIT_FAILED ) {
180- psutil_debug ("WaitForSingleObject -> WAIT_FAILED" );
181- if (TerminateThread (hThread , 0 ) == 0 ) {
182- PyErr_SetFromOSErrnoWithSyscall (
183- "WaitForSingleObject -> WAIT_FAILED -> TerminateThread" );
184- CloseHandle (hThread );
185- return 1 ;
186- }
187- PyErr_SetFromOSErrnoWithSyscall ("WaitForSingleObject" );
188- CloseHandle (hThread );
189- return 1 ;
182+ if (! NT_SUCCESS (threadContext .status )) {
183+ psutil_SetFromNTStatusErr (threadContext .status , "NtQuerySystemInformation" );
184+ FREE (threadContext .FileName );
185+ return NULL ;
190186 }
191187
192- if (GetExitCodeThread (hThread , & threadRetValue ) == 0 ) {
193- if (TerminateThread (hThread , 0 ) == 0 ) {
194- PyErr_SetFromOSErrnoWithSyscall (
195- "GetExitCodeThread (failed) -> TerminateThread" );
196- CloseHandle (hThread );
197- return 1 ;
198- }
199-
200- CloseHandle (hThread );
201- PyErr_SetFromOSErrnoWithSyscall ("GetExitCodeThread" );
202- return 1 ;
203- }
204- CloseHandle (hThread );
205- return threadRetValue ;
188+ return threadContext .FileName ;
206189}
207190
208191
@@ -214,15 +197,12 @@ psutil_get_open_files(DWORD dwPid, HANDLE hProcess) {
214197 ULONG i = 0 ;
215198 BOOLEAN errorOccurred = FALSE;
216199 PyObject * py_path = NULL ;
217- PyObject * py_retlist = PyList_New (0 );;
200+ PyObject * py_retlist = PyList_New (0 );
201+ PUNICODE_STRING fileName = NULL ;
218202
219203 if (!py_retlist )
220204 return NULL ;
221205
222- // Due to the use of global variables, ensure only 1 call
223- // to psutil_get_open_files() is running.
224- EnterCriticalSection (& PSUTIL_CRITICAL_SECTION );
225-
226206 if (psutil_enum_handles (& handlesList ) != 0 )
227207 goto error ;
228208
@@ -243,13 +223,20 @@ psutil_get_open_files(DWORD dwPid, HANDLE hProcess) {
243223 continue ;
244224 }
245225
246- // This will set *globalFileName* global variable.
247- if (psutil_threaded_get_filename (hFile ) != 0 )
226+ if (GetFileType (hFile ) != FILE_TYPE_DISK ) {
227+ SetLastError (0 );
228+ CloseHandle (hFile );
229+ hFile = NULL ;
230+ continue ;
231+ }
232+
233+ fileName = psutil_threaded_get_filename (hFile );
234+ if (fileName == NULL )
248235 goto error ;
249236
250- if ((globalFileName != NULL ) && (globalFileName -> Length > 0 )) {
251- py_path = PyUnicode_FromWideChar (globalFileName -> Buffer ,
252- wcslen (globalFileName -> Buffer ));
237+ if ((fileName != NULL ) && (fileName -> Length > 0 )) {
238+ py_path = PyUnicode_FromWideChar (fileName -> Buffer ,
239+ wcslen (fileName -> Buffer ));
253240 if (! py_path )
254241 goto error ;
255242 if (PyList_Append (py_retlist , py_path ))
@@ -258,9 +245,9 @@ psutil_get_open_files(DWORD dwPid, HANDLE hProcess) {
258245 }
259246
260247 // Loop cleanup section.
261- if (globalFileName != NULL ) {
262- FREE (globalFileName );
263- globalFileName = NULL ;
248+ if (fileName != NULL ) {
249+ FREE (fileName );
250+ fileName = NULL ;
264251 }
265252 CloseHandle (hFile );
266253 hFile = NULL ;
@@ -276,16 +263,13 @@ psutil_get_open_files(DWORD dwPid, HANDLE hProcess) {
276263exit :
277264 if (hFile != NULL )
278265 CloseHandle (hFile );
279- if (globalFileName != NULL ) {
280- FREE (globalFileName );
281- globalFileName = NULL ;
282- }
266+ if (fileName != NULL )
267+ FREE (fileName );
283268 if (py_path != NULL )
284269 Py_DECREF (py_path );
285270 if (handlesList != NULL )
286271 FREE (handlesList );
287272
288- LeaveCriticalSection (& PSUTIL_CRITICAL_SECTION );
289273 if (errorOccurred == TRUE)
290274 return NULL ;
291275 return py_retlist ;
0 commit comments