Index: third_party/psutil/psutil/_psutil_mswindows.c |
diff --git a/third_party/psutil/psutil/_psutil_mswindows.c b/third_party/psutil/psutil/_psutil_mswindows.c |
index 94f9057e6641493a8d4720ff505dcee8422189d8..3964179ab97273ed3d401a1fab9bab55760a4767 100644 |
--- a/third_party/psutil/psutil/_psutil_mswindows.c |
+++ b/third_party/psutil/psutil/_psutil_mswindows.c |
@@ -1,5 +1,9 @@ |
/* |
- * $Id: _psutil_mswindows.c 796 2010-11-12 20:31:28Z g.rodola $ |
+ * $Id: _psutil_mswindows.c 1142 2011-10-05 18:45:49Z g.rodola $ |
+ * |
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
* |
* Windows platform-specific module methods for _psutil_mswindows |
*/ |
@@ -14,147 +18,13 @@ |
#include <iphlpapi.h> |
#include "_psutil_mswindows.h" |
+#include "_psutil_common.h" |
#include "arch/mswindows/security.h" |
#include "arch/mswindows/process_info.h" |
#include "arch/mswindows/process_handles.h" |
+#include "arch/mswindows/ntextapi.h" |
-// ------------------------ Python init --------------------------- |
- |
-static PyMethodDef |
-PsutilMethods[] = |
-{ |
- // --- per-process functions |
- |
- {"get_process_name", get_process_name, METH_VARARGS, |
- "Return process name"}, |
- {"get_process_cmdline", get_process_cmdline, METH_VARARGS, |
- "Return process cmdline as a list of cmdline arguments"}, |
- {"get_process_ppid", get_process_ppid, METH_VARARGS, |
- "Return process ppid as an integer"}, |
- {"kill_process", kill_process, METH_VARARGS, |
- "Kill the process identified by the given PID"}, |
- {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, |
- "Return tuple of user/kern time for the given PID"}, |
- {"get_process_create_time", get_process_create_time, METH_VARARGS, |
- "Return a float indicating the process create time expressed in " |
- "seconds since the epoch"}, |
- {"get_memory_info", get_memory_info, METH_VARARGS, |
- "Return a tuple of RSS/VMS memory information"}, |
- {"get_process_cwd", get_process_cwd, METH_VARARGS, |
- "Return process current working directory"}, |
- {"suspend_process", suspend_process, METH_VARARGS, |
- "Suspend a process"}, |
- {"resume_process", resume_process, METH_VARARGS, |
- "Resume a process"}, |
- {"get_process_open_files", get_process_open_files, METH_VARARGS, |
- "Return files opened by process"}, |
- {"_QueryDosDevice", _QueryDosDevice, METH_VARARGS, |
- "QueryDosDevice binding"}, |
- {"get_process_username", get_process_username, METH_VARARGS, |
- "Return the username of a process"}, |
- {"get_process_connections", get_process_connections, METH_VARARGS, |
- "Return the network connections of a process"}, |
- {"get_process_num_threads", get_process_num_threads, METH_VARARGS, |
- "Return the network connections of a process"}, |
- |
- // --- system-related functions |
- |
- {"get_pid_list", get_pid_list, METH_VARARGS, |
- "Returns a list of PIDs currently running on the system"}, |
- {"pid_exists", pid_exists, METH_VARARGS, |
- "Determine if the process exists in the current process list."}, |
- {"get_num_cpus", get_num_cpus, METH_VARARGS, |
- "Returns the number of CPUs on the system"}, |
- {"get_system_uptime", get_system_uptime, METH_VARARGS, |
- "Return system uptime"}, |
- {"get_total_phymem", get_total_phymem, METH_VARARGS, |
- "Return the total amount of physical memory, in bytes"}, |
- {"get_total_virtmem", get_total_virtmem, METH_VARARGS, |
- "Return the total amount of virtual memory, in bytes"}, |
- {"get_avail_phymem", get_avail_phymem, METH_VARARGS, |
- "Return the amount of available physical memory, in bytes"}, |
- {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS, |
- "Return the amount of available virtual memory, in bytes"}, |
- {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, |
- "Return system cpu times as a tuple (user, system, idle)"}, |
- |
- {NULL, NULL, 0, NULL} |
-}; |
- |
- |
-struct module_state { |
- PyObject *error; |
-}; |
- |
-#if PY_MAJOR_VERSION >= 3 |
- #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) |
-#else |
- #define GETSTATE(m) (&_state) |
- static struct module_state _state; |
-#endif |
- |
-#if PY_MAJOR_VERSION >= 3 |
- |
- static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) { |
- Py_VISIT(GETSTATE(m)->error); |
- return 0; |
- } |
- |
- static int psutil_mswindows_clear(PyObject *m) { |
- Py_CLEAR(GETSTATE(m)->error); |
- return 0; |
- } |
- |
- static struct PyModuleDef moduledef = { |
- PyModuleDef_HEAD_INIT, |
- "psutil_mswindows", |
- NULL, |
- sizeof(struct module_state), |
- PsutilMethods, |
- NULL, |
- psutil_mswindows_traverse, |
- psutil_mswindows_clear, |
- NULL |
- }; |
- |
-#define INITERROR return NULL |
- |
- PyObject* PyInit__psutil_mswindows(void) |
- |
-#else |
- #define INITERROR return |
- void init_psutil_mswindows(void) |
-#endif |
-{ |
- struct module_state *st = NULL; |
-#if PY_MAJOR_VERSION >= 3 |
- PyObject *module = PyModule_Create(&moduledef); |
-#else |
- PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods); |
-#endif |
- |
- if (module == NULL) { |
- INITERROR; |
- } |
- |
- st = GETSTATE(module); |
- st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL); |
- if (st->error == NULL) { |
- Py_DECREF(module); |
- INITERROR; |
- } |
- |
- SetSeDebug(); |
- |
-#if PY_MAJOR_VERSION >= 3 |
- return module; |
-#endif |
-} |
- |
- |
-// ------------------------ Public functions --------------------------- |
- |
/* |
* Return a Python float representing the system uptime expressed in seconds |
* since the epoch. |
@@ -253,10 +123,12 @@ kill_process(PyObject* self, PyObject* args) |
HANDLE hProcess; |
long pid; |
- if (! PyArg_ParseTuple(args, "l", &pid)) |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
return NULL; |
- if (pid == 0) |
+ } |
+ if (pid == 0) { |
return AccessDenied(); |
+ } |
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); |
if (hProcess == NULL) { |
@@ -283,6 +155,67 @@ kill_process(PyObject* self, PyObject* args) |
} |
+/* |
+ * Wait for process to terminate and return its exit code. |
+ */ |
+static PyObject* |
+process_wait(PyObject* self, PyObject* args) |
+{ |
+ HANDLE hProcess; |
+ DWORD ExitCode; |
+ DWORD retVal; |
+ long pid; |
+ long timeout; |
+ |
+ if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) { |
+ return NULL; |
+ } |
+ if (pid == 0) { |
+ return AccessDenied(); |
+ } |
+ |
+ hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); |
+ if (hProcess == NULL) { |
+ if (GetLastError() == ERROR_INVALID_PARAMETER) { |
+ // no such process; we do not want to raise NSP but |
+ // return None instead. |
+ Py_INCREF(Py_None); |
+ return Py_None; |
+ } |
+ else { |
+ PyErr_SetFromWindowsErr(0); |
+ return NULL; |
+ } |
+ } |
+ |
+ // wait until the process has terminated |
+ Py_BEGIN_ALLOW_THREADS |
+ retVal = WaitForSingleObject(hProcess, timeout); |
+ Py_END_ALLOW_THREADS |
+ |
+ if (retVal == WAIT_FAILED) { |
+ CloseHandle(hProcess); |
+ return PyErr_SetFromWindowsErr(GetLastError()); |
+ } |
+ if (retVal == WAIT_TIMEOUT) { |
+ CloseHandle(hProcess); |
+ return Py_BuildValue("l", WAIT_TIMEOUT); |
+ } |
+ |
+ // get the exit code; note: subprocess module (erroneously?) uses |
+ // what returned by WaitForSingleObject |
+ if (GetExitCodeProcess(hProcess, &ExitCode) == 0) { |
+ CloseHandle(hProcess); |
+ return PyErr_SetFromWindowsErr(GetLastError()); |
+ } |
+ CloseHandle(hProcess); |
+#if PY_MAJOR_VERSION >= 3 |
+ return PyLong_FromLong((long) ExitCode); |
+#else |
+ return PyInt_FromLong((long) ExitCode); |
+#endif |
+} |
+ |
/* |
* Return a Python tuple (user_time, kernel_time) |
@@ -309,15 +242,16 @@ get_process_cpu_times(PyObject* self, PyObject* args) |
} |
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { |
+ CloseHandle(hProcess); |
if (GetLastError() == ERROR_ACCESS_DENIED) { |
// usually means the process has died so we throw a NoSuchProcess |
// here |
- CloseHandle(hProcess); |
return NoSuchProcess(); |
} |
- PyErr_SetFromWindowsErr(0); |
- CloseHandle(hProcess); |
- return NULL; |
+ else { |
+ PyErr_SetFromWindowsErr(0); |
+ return NULL; |
+ } |
} |
CloseHandle(hProcess); |
@@ -370,15 +304,15 @@ get_process_create_time(PyObject* self, PyObject* args) |
} |
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { |
+ CloseHandle(hProcess); |
if (GetLastError() == ERROR_ACCESS_DENIED) { |
// usually means the process has died so we throw a NoSuchProcess here |
return NoSuchProcess(); |
} |
else { |
PyErr_SetFromWindowsErr(0); |
+ return NULL; |
} |
- CloseHandle(hProcess); |
- return NULL; |
} |
CloseHandle(hProcess); |
@@ -421,8 +355,9 @@ get_process_name(PyObject* self, PyObject* args) { |
int pid_return; |
PyObject* name; |
- if (! PyArg_ParseTuple(args, "l", &pid)) |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
return NULL; |
+ } |
if (pid == 0) { |
return Py_BuildValue("s", "System Idle Process"); |
@@ -440,8 +375,9 @@ get_process_name(PyObject* self, PyObject* args) { |
} |
name = get_name(pid); |
- if (name == NULL) |
+ if (name == NULL) { |
return NULL; // exception set in get_name() |
+ } |
return name; |
} |
@@ -455,10 +391,12 @@ get_process_ppid(PyObject* self, PyObject* args) { |
int pid_return; |
PyObject* ppid; |
- if (! PyArg_ParseTuple(args, "l", &pid)) |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
return NULL; |
- if ((pid == 0) || (pid == 4)) |
+ } |
+ if ((pid == 0) || (pid == 4)) { |
return Py_BuildValue("l", 0); |
+ } |
pid_return = pid_is_running(pid); |
if (pid_return == 0) { |
@@ -469,8 +407,9 @@ get_process_ppid(PyObject* self, PyObject* args) { |
} |
ppid = get_ppid(pid); |
- if (ppid == NULL) |
+ if (ppid == NULL) { |
return NULL; // exception set in get_ppid() |
+ } |
return ppid; |
} |
@@ -483,10 +422,12 @@ get_process_cmdline(PyObject* self, PyObject* args) { |
int pid_return; |
PyObject* arglist; |
- if (! PyArg_ParseTuple(args, "l", &pid)) |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
return NULL; |
- if ((pid == 0) || (pid == 4)) |
+ } |
+ if ((pid == 0) || (pid == 4)) { |
return Py_BuildValue("[]"); |
+ } |
pid_return = pid_is_running(pid); |
if (pid_return == 0) { |
@@ -529,9 +470,11 @@ get_memory_info(PyObject* self, PyObject* args) |
} |
if (! GetProcessMemoryInfo(hProcess, &counters, sizeof(counters)) ) { |
+ CloseHandle(hProcess); |
return PyErr_SetFromWindowsErr(0); |
} |
+ CloseHandle(hProcess); |
return Py_BuildValue("(nn)", counters.WorkingSetSize, counters.PagefileUsage); |
} |
@@ -541,7 +484,7 @@ get_memory_info(PyObject* self, PyObject* args) |
* in bytes. |
*/ |
static PyObject* |
-get_total_phymem(PyObject* self, PyObject* args) |
+get_system_phymem(PyObject* self, PyObject* args) |
{ |
MEMORYSTATUSEX memInfo; |
memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
@@ -550,255 +493,106 @@ get_total_phymem(PyObject* self, PyObject* args) |
return PyErr_SetFromWindowsErr(0); |
} |
- return Py_BuildValue("L", memInfo.ullTotalPhys); |
-} |
- |
- |
-/* |
- * Return a Python integer indicating the total amount of virtual memory |
- * in bytes. |
- */ |
-static PyObject* |
-get_total_virtmem(PyObject* self, PyObject* args) |
-{ |
- MEMORYSTATUSEX memInfo; |
- memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
- |
- if (! GlobalMemoryStatusEx(&memInfo) ) { |
- return PyErr_SetFromWindowsErr(0); |
- } |
- |
- return Py_BuildValue("L", memInfo.ullTotalPageFile); |
-} |
- |
- |
-/* |
- * Return a Python integer indicating the amount of available physical memory |
- * in bytes. |
- */ |
-static PyObject* |
-get_avail_phymem(PyObject* self, PyObject* args) |
-{ |
- MEMORYSTATUSEX memInfo; |
- memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
- if (! GlobalMemoryStatusEx(&memInfo) ) { |
- return PyErr_SetFromWindowsErr(0); |
- } |
- return Py_BuildValue("L", memInfo.ullAvailPhys); |
-} |
- |
- |
-/* |
- * Return a Python integer indicating the amount of available virtual memory |
- * in bytes. |
- */ |
-static PyObject* |
-get_avail_virtmem(PyObject* self, PyObject* args) |
-{ |
- MEMORYSTATUSEX memInfo; |
- memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
- |
- if (! GlobalMemoryStatusEx(&memInfo) ) { |
- return PyErr_SetFromWindowsErr(0); |
- } |
- return Py_BuildValue("L", memInfo.ullAvailPageFile); |
+ return Py_BuildValue("(LLLLLLk)", |
+ memInfo.ullTotalPhys, // total |
+ memInfo.ullAvailPhys, // avail |
+ memInfo.ullTotalPageFile, // total page file |
+ memInfo.ullAvailPageFile, // avail page file |
+ memInfo.ullTotalVirtual, // total virtual |
+ memInfo.ullAvailVirtual, // avail virtual |
+ memInfo.dwMemoryLoad // percent |
+ ); |
} |
#define LO_T ((float)1e-7) |
#define HI_T (LO_T*4294967296.0) |
-// structures and enums from winternl.h (not available under mingw) |
-typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { |
- LARGE_INTEGER IdleTime; |
- LARGE_INTEGER KernelTime; |
- LARGE_INTEGER UserTime; |
- LARGE_INTEGER Reserved1[2]; |
- ULONG Reserved2; |
-} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; |
- |
- |
-typedef enum _SYSTEM_INFORMATION_CLASS { |
- SystemBasicInformation = 0, |
- SystemPerformanceInformation = 2, |
- SystemTimeOfDayInformation = 3, |
- SystemProcessInformation = 5, |
- SystemProcessorPerformanceInformation = 8, |
- SystemInterruptInformation = 23, |
- SystemExceptionInformation = 33, |
- SystemRegistryQuotaInformation = 37, |
- SystemLookasideInformation = 45 |
-} SYSTEM_INFORMATION_CLASS; |
- |
/* |
- * Return a Python tuple representing user, kernel and idle CPU times |
+ * Return a Python list of tuples representing user, kernel and idle |
+ * CPU times for every CPU on the system. |
*/ |
static PyObject* |
get_system_cpu_times(PyObject* self, PyObject* args) |
{ |
- typedef BOOL (_stdcall *GST_PROC) (LPFILETIME, LPFILETIME, LPFILETIME); |
- static GST_PROC GetSystemTimes; |
- static BOOL bFirstCall = TRUE; |
float idle, kernel, user; |
- |
- // Improves performance calling GetProcAddress only the first time |
- if (bFirstCall) { |
- // retrieves GetSystemTimes address in Kernel32 |
- GetSystemTimes=(GST_PROC)GetProcAddress(GetModuleHandle |
- (TEXT("Kernel32.dll")), |
- "GetSystemTimes"); |
- bFirstCall = FALSE; |
- } |
- |
- |
- // Uses GetSystemTimes if supported (winXP sp1+) |
- if (NULL!=GetSystemTimes) { |
- // GetSystemTimes supported |
- |
- FILETIME idle_time; |
- FILETIME kernel_time; |
- FILETIME user_time; |
- |
- if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) { |
- return PyErr_SetFromWindowsErr(0); |
- } |
- |
- idle = (float)((HI_T * idle_time.dwHighDateTime) + \ |
- (LO_T * idle_time.dwLowDateTime)); |
- user = (float)((HI_T * user_time.dwHighDateTime) + \ |
- (LO_T * user_time.dwLowDateTime)); |
- kernel = (float)((HI_T * kernel_time.dwHighDateTime) + \ |
- (LO_T * kernel_time.dwLowDateTime)); |
- |
- // kernel time includes idle time on windows |
- // we return only busy kernel time subtracting idle time from kernel time |
- return Py_BuildValue("(fff)", user, |
- kernel - idle, |
- idle); |
- |
- } |
- |
- else { |
- // GetSystemTimes NOT supported, use NtQuerySystemInformation instead |
- |
- typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG); |
- NTQSI_PROC NtQuerySystemInformation; |
- HINSTANCE hNtDll; |
- SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; |
- SYSTEM_INFO si; |
- UINT i; |
- |
- // dynamic linking is mandatory to use NtQuerySystemInformation |
- hNtDll = LoadLibrary(TEXT("ntdll.dll")); |
- if (hNtDll != NULL) { |
- // gets NtQuerySystemInformation address |
- NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( |
- hNtDll, "NtQuerySystemInformation"); |
- |
- if (NtQuerySystemInformation != NULL) |
+ typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG); |
+ NTQSI_PROC NtQuerySystemInformation; |
+ HINSTANCE hNtDll; |
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; |
+ SYSTEM_INFO si; |
+ UINT i; |
+ PyObject *arg = NULL; |
+ PyObject *retlist = PyList_New(0); |
+ |
+ // dynamic linking is mandatory to use NtQuerySystemInformation |
+ hNtDll = LoadLibrary(TEXT("ntdll.dll")); |
+ if (hNtDll != NULL) { |
+ // gets NtQuerySystemInformation address |
+ NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( |
+ hNtDll, "NtQuerySystemInformation"); |
+ |
+ if (NtQuerySystemInformation != NULL) |
+ { |
+ // retrives number of processors |
+ GetSystemInfo(&si); |
+ |
+ // allocates an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION |
+ // structures, one per processor |
+ sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ |
+ malloc(si.dwNumberOfProcessors * \ |
+ sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); |
+ if (sppi != NULL) |
{ |
- // retrives number of processors |
- GetSystemInfo(&si); |
- |
- // allocates an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION |
- // structures, one per processor |
- sppi=(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ |
- malloc(si.dwNumberOfProcessors * \ |
- sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); |
- if (sppi != NULL) |
+ // gets cpu time informations |
+ if (0 == NtQuerySystemInformation( |
+ SystemProcessorPerformanceInformation, |
+ sppi, |
+ si.dwNumberOfProcessors * sizeof |
+ (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), |
+ NULL) |
+ ) |
{ |
- // gets cpu time informations |
- if (0 == NtQuerySystemInformation( |
- SystemProcessorPerformanceInformation, |
- sppi, |
- si.dwNumberOfProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), |
- NULL)) |
- { |
- // computes system global times summing each processor value |
- idle = user = kernel = 0; |
- for (i=0; i<si.dwNumberOfProcessors; i++) { |
- idle += (float)((HI_T * sppi[i].IdleTime.HighPart) + \ |
- (LO_T * sppi[i].IdleTime.LowPart)); |
- user += (float)((HI_T * sppi[i].UserTime.HighPart) + \ |
- (LO_T * sppi[i].UserTime.LowPart)); |
- kernel += (float)((HI_T * sppi[i].KernelTime.HighPart) + \ |
- (LO_T * sppi[i].KernelTime.LowPart)); |
- } |
- |
+ // computes system global times summing each processor value |
+ idle = user = kernel = 0; |
+ for (i=0; i<si.dwNumberOfProcessors; i++) { |
+ user = (float)((HI_T * sppi[i].UserTime.HighPart) + \ |
+ (LO_T * sppi[i].UserTime.LowPart)); |
+ idle = (float)((HI_T * sppi[i].IdleTime.HighPart) + \ |
+ (LO_T * sppi[i].IdleTime.LowPart)); |
+ kernel = (float)((HI_T * sppi[i].KernelTime.HighPart) + \ |
+ (LO_T * sppi[i].KernelTime.LowPart)); |
// kernel time includes idle time on windows |
- // we return only busy kernel time subtracting idle |
- // time from kernel time |
- return Py_BuildValue("(ddd)", user, |
- kernel - idle, |
- idle |
- ); |
- |
- } // END NtQuerySystemInformation |
- |
- } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION |
- |
- } // END GetProcAddress |
- |
- } // END LoadLibrary |
- |
- PyErr_SetFromWindowsErr(0); |
- if (sppi) { |
- free(sppi); |
- } |
- if (hNtDll) { |
- FreeLibrary(hNtDll); |
- } |
- return 0; |
- |
- } // END GetSystemTimes NOT supported |
+ // we return only busy kernel time subtracting |
+ // idle time from kernel time |
+ arg = Py_BuildValue("(ddd)", user, |
+ kernel - idle, |
+ idle); |
+ PyList_Append(retlist, arg); |
+ Py_XDECREF(arg); |
+ } |
+ free(sppi); |
+ FreeLibrary(hNtDll); |
+ return retlist; |
+ |
+ } // END NtQuerySystemInformation |
+ } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION |
+ } // END GetProcAddress |
+ } // END LoadLibrary |
+ |
+ if (sppi) { |
+ free(sppi); |
+ } |
+ if (hNtDll) { |
+ FreeLibrary(hNtDll); |
+ } |
+ PyErr_SetFromWindowsErr(0); |
+ return NULL; |
} |
/* |
- * Sid to User convertion |
- */ |
-BOOL SidToUser(PSID pSid, LPTSTR szUser, DWORD dwUserLen, LPTSTR szDomain, DWORD |
-dwDomainLen, DWORD pid) |
-{ |
- SID_NAME_USE snuSIDNameUse; |
- DWORD dwULen; |
- DWORD dwDLen; |
- |
- dwULen = dwUserLen; |
- dwDLen = dwDomainLen; |
- |
- if ( IsValidSid( pSid ) ) { |
- // Get user and domain name based on SID |
- if ( LookupAccountSid( NULL, pSid, szUser, &dwULen, szDomain, &dwDLen, &snuSIDNameUse) ) { |
- // LocalSystem processes are incorrectly reported as owned |
- // by BUILTIN\Administrators We modify that behavior to |
- // conform to standard taskmanager only if the process is |
- // actually a System process |
- if (is_system_proc(pid) == 1) { |
- // default to *not* changing the data if we fail to |
- // check for local system privileges, so only look for |
- // definite confirmed system processes and ignore errors |
- if ( lstrcmpi(szDomain, TEXT("builtin")) == 0 && lstrcmpi(szUser, TEXT("administrators")) == 0) { |
- strncpy (szUser, "SYSTEM", dwUserLen); |
- strncpy (szDomain, "NT AUTHORITY", dwDomainLen); |
- } |
- } |
- |
- return TRUE; |
- } |
- } |
- |
- return FALSE; |
-} |
- |
-typedef struct _UNICODE_STRING { |
- USHORT Length; |
- USHORT MaximumLength; |
- PWSTR Buffer; |
-} UNICODE_STRING, *PUNICODE_STRING; |
- |
-/* |
* Return process current working directory as a Python string. |
*/ |
@@ -922,6 +716,11 @@ suspend_resume_process(DWORD pid, int suspend) |
HANDLE hThreadSnap = NULL; |
THREADENTRY32 te32 = {0}; |
+ if (pid == 0) { |
+ AccessDenied(); |
+ return FALSE; |
+ } |
+ |
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
if (hThreadSnap == INVALID_HANDLE_VALUE) { |
PyErr_SetFromWindowsErr(0); |
@@ -1015,14 +814,44 @@ resume_process(PyObject* self, PyObject* args) |
static PyObject* |
get_process_num_threads(PyObject* self, PyObject* args) |
{ |
- long pid; |
- int pid_return; |
- long nthreads = 0; |
+ DWORD pid; |
+ PSYSTEM_PROCESS_INFORMATION process; |
+ PVOID buffer; |
+ int num; |
+ |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
+ return NULL; |
+ } |
+ if (get_process_info(pid, &process, &buffer) != 1) { |
+ free(buffer); |
+ return NULL; |
+ } |
+ if (pid_is_running(pid) == 0) { |
+ free(buffer); |
+ return NoSuchProcess(); |
+ } |
+ |
+ num = (int)process->NumberOfThreads; |
+ free(buffer); |
+ return Py_BuildValue("i", num); |
+} |
+ |
+ |
+static PyObject* |
+get_process_threads(PyObject* self, PyObject* args) |
+{ |
+ PyObject* retList = PyList_New(0); |
+ PyObject* pyTuple = NULL; |
HANDLE hThreadSnap = NULL; |
THREADENTRY32 te32 = {0}; |
+ long pid; |
+ int pid_return; |
+ int rc; |
+ FILETIME ftDummy, ftKernel, ftUser; |
- if (! PyArg_ParseTuple(args, "l", &pid)) |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
return NULL; |
+ } |
if (pid == 0) { |
// raise AD instead of returning 0 as procexp is able to |
// retrieve useful information somehow |
@@ -1061,30 +890,48 @@ get_process_num_threads(PyObject* self, PyObject* args) |
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, |
FALSE, te32.th32ThreadID); |
if (hThread == NULL) { |
- if (GetLastError() == ERROR_INVALID_PARAMETER) { |
- NoSuchProcess(); |
- } |
- else { |
- PyErr_SetFromWindowsErr(0); |
- } |
+ // thread has disappeared on us |
+ continue; |
+ } |
+ |
+ rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser); |
+ if (rc == 0) { |
+ PyErr_SetFromWindowsErr(0); |
CloseHandle(hThread); |
CloseHandle(hThreadSnap); |
return NULL; |
} |
- nthreads += 1; |
+ |
+ /* |
+ user and kernel times are represented as a FILETIME structure |
+ wich contains a 64-bit value representing the number of |
+ 100-nanosecond intervals since January 1, 1601 (UTC). |
+ http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx |
+ |
+ To convert it into a float representing the seconds that the |
+ process has executed in user/kernel mode I borrowed the code |
+ below from Python's Modules/posixmodule.c |
+ */ |
+ pyTuple = Py_BuildValue("kdd", |
+ te32.th32ThreadID, |
+ (double)(ftUser.dwHighDateTime*429.4967296 + \ |
+ ftUser.dwLowDateTime*1e-7), |
+ (double)(ftKernel.dwHighDateTime*429.4967296 + \ |
+ ftKernel.dwLowDateTime*1e-7) |
+ ); |
+ PyList_Append(retList, pyTuple); |
+ Py_XDECREF(pyTuple); |
+ |
CloseHandle(hThread); |
} |
} while (Thread32Next(hThreadSnap, &te32)); |
- // every process should be supposed to have at least one thread |
- if (nthreads == 0) { |
- return NoSuchProcess(); |
- } |
- |
- return Py_BuildValue("l", nthreads); |
+ CloseHandle(hThreadSnap); |
+ return retList; |
} |
+ |
static PyObject* |
get_process_open_files(PyObject* self, PyObject* args) |
{ |
@@ -1103,6 +950,7 @@ get_process_open_files(PyObject* self, PyObject* args) |
} |
filesList = get_open_files(pid, processHandle); |
+ CloseHandle(processHandle); |
if (filesList == NULL) { |
return PyErr_SetFromWindowsErr(0); |
} |
@@ -1116,7 +964,7 @@ get_process_open_files(PyObject* self, PyObject* args) |
If no match is found return an empty string. |
*/ |
static PyObject* |
-_QueryDosDevice(PyObject* self, PyObject* args) |
+win32_QueryDosDevice(PyObject* self, PyObject* args) |
{ |
LPCTSTR lpDevicePath; |
TCHAR d = TEXT('A'); |
@@ -1441,8 +1289,9 @@ get_process_connections(PyObject* self, PyObject* args) |
for (i = 0; i < tcp4Table->dwNumEntries; i++) |
{ |
- if (tcp4Table->table[i].dwOwningPid != pid) |
+ if (tcp4Table->table[i].dwOwningPid != pid) { |
continue; |
+ } |
if (tcp4Table->table[i].dwLocalAddr != 0 || |
tcp4Table->table[i].dwLocalPort != 0) |
@@ -1572,8 +1421,9 @@ get_process_connections(PyObject* self, PyObject* args) |
for (i = 0; i < udp4Table->dwNumEntries; i++) |
{ |
- if (udp4Table->table[i].dwOwningPid != pid) |
+ if (udp4Table->table[i].dwOwningPid != pid) { |
continue; |
+ } |
if (udp4Table->table[i].dwLocalAddr != 0 || |
udp4Table->table[i].dwLocalPort != 0) |
@@ -1653,3 +1503,395 @@ get_process_connections(PyObject* self, PyObject* args) |
return connectionsList; |
} |
+ |
+/* |
+ * Get process priority as a Python integer. |
+ */ |
+static PyObject* |
+get_process_priority(PyObject* self, PyObject* args) |
+{ |
+ long pid; |
+ DWORD priority; |
+ HANDLE hProcess; |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
+ return NULL; |
+ } |
+ |
+ hProcess = handle_from_pid(pid); |
+ if (hProcess == NULL) { |
+ return NULL; |
+ } |
+ |
+ priority = GetPriorityClass(hProcess); |
+ CloseHandle(hProcess); |
+ if (priority == 0) { |
+ PyErr_SetFromWindowsErr(0); |
+ return NULL; |
+ } |
+ return Py_BuildValue("i", priority); |
+} |
+ |
+ |
+/* |
+ * Set process priority. |
+ */ |
+static PyObject* |
+set_process_priority(PyObject* self, PyObject* args) |
+{ |
+ long pid; |
+ int priority; |
+ int retval; |
+ HANDLE hProcess; |
+ DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; |
+ if (! PyArg_ParseTuple(args, "li", &pid, &priority)) { |
+ return NULL; |
+ } |
+ |
+ hProcess = handle_from_pid_waccess(pid, dwDesiredAccess); |
+ if (hProcess == NULL) { |
+ return NULL; |
+ } |
+ |
+ retval = SetPriorityClass(hProcess, priority); |
+ CloseHandle(hProcess); |
+ if (retval == 0) { |
+ PyErr_SetFromWindowsErr(0); |
+ return NULL; |
+ } |
+ Py_INCREF(Py_None); |
+ return Py_None; |
+} |
+ |
+ |
+/* |
+ * Return a Python tuple referencing process I/O counters. |
+ */ |
+static PyObject* |
+get_process_io_counters(PyObject* self, PyObject* args) |
+{ |
+ DWORD pid; |
+ HANDLE hProcess; |
+ IO_COUNTERS IoCounters; |
+ |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
+ return NULL; |
+ } |
+ if (pid == 0) { |
+ return AccessDenied(); |
+ } |
+ hProcess = handle_from_pid(pid); |
+ if (NULL == hProcess) { |
+ return NULL; |
+ } |
+ if (! GetProcessIoCounters(hProcess, &IoCounters)) { |
+ CloseHandle(hProcess); |
+ return PyErr_SetFromWindowsErr(0); |
+ } |
+ CloseHandle(hProcess); |
+ return Py_BuildValue("(KKKK)", IoCounters.ReadOperationCount, |
+ IoCounters.WriteOperationCount, |
+ IoCounters.ReadTransferCount, |
+ IoCounters.WriteTransferCount); |
+} |
+ |
+ |
+/* |
+ * Return True if one of the process threads is in a waiting or |
+ * suspended status. |
+ */ |
+static PyObject* |
+is_process_suspended(PyObject* self, PyObject* args) |
+{ |
+ DWORD pid; |
+ ULONG i; |
+ PSYSTEM_PROCESS_INFORMATION process; |
+ PVOID buffer; |
+ |
+ if (! PyArg_ParseTuple(args, "l", &pid)) { |
+ return NULL; |
+ } |
+ if (get_process_info(pid, &process, &buffer) != 1) { |
+ free(buffer); |
+ return NULL; |
+ } |
+ if (pid_is_running(pid) == 0) { |
+ free(buffer); |
+ return NoSuchProcess(); |
+ } |
+ |
+ for (i = 0; i < process->NumberOfThreads; i++) { |
+ if (process->Threads[i].ThreadState != Waiting || |
+ process->Threads[i].WaitReason != Suspended) |
+ { |
+ free(buffer); |
+ Py_RETURN_FALSE; |
+ } |
+ } |
+ free(buffer); |
+ Py_RETURN_TRUE; |
+} |
+ |
+ |
+/* |
+ * Return path's disk total and free as a Python tuple. |
+ */ |
+static PyObject* |
+get_disk_usage(PyObject* self, PyObject* args) |
+{ |
+ BOOL retval; |
+ ULARGE_INTEGER _, total, free; |
+ LPCTSTR path; |
+ |
+ if (! PyArg_ParseTuple(args, "s", &path)) { |
+ return NULL; |
+ } |
+ |
+ Py_BEGIN_ALLOW_THREADS |
+ retval = GetDiskFreeSpaceEx(path, &_, &total, &free); |
+ Py_END_ALLOW_THREADS |
+ if (retval == 0) { |
+ return PyErr_SetFromWindowsErr(0); |
+ } |
+ |
+ return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); |
+} |
+ |
+ |
+/* |
+ * Return disk partitions as a list of namedtuples. |
+ */ |
+static PyObject* |
+win32_GetLogicalDriveStrings(PyObject* self, PyObject* args) |
+{ |
+ DWORD num_bytes; |
+ char drive_strings[255]; |
+ char* drive_letter = drive_strings; |
+ PyObject* py_retlist = PyList_New(0); |
+ |
+ Py_BEGIN_ALLOW_THREADS |
+ num_bytes = GetLogicalDriveStrings(254, drive_letter); |
+ Py_END_ALLOW_THREADS |
+ |
+ if (num_bytes == 0) { |
+ return PyErr_SetFromWindowsErr(0); |
+ } |
+ |
+ while (*drive_letter != 0) { |
+ PyList_Append(py_retlist, Py_BuildValue("s", drive_letter)); |
+ drive_letter = strchr(drive_letter, 0) +1; |
+ } |
+ |
+ return py_retlist; |
+} |
+ |
+ |
+static PyObject* |
+win32_GetDriveType(PyObject* self, PyObject* args) |
+{ |
+ LPCTSTR drive_letter; |
+ int type; |
+ char* type_str; |
+ |
+ if (! PyArg_ParseTuple(args, "s", &drive_letter)) { |
+ return NULL; |
+ } |
+ |
+ Py_BEGIN_ALLOW_THREADS |
+ type = GetDriveType(drive_letter); |
+ Py_END_ALLOW_THREADS |
+ |
+ switch (type) { |
+ case DRIVE_UNKNOWN: |
+ type_str = "unknown"; |
+ break; |
+ case DRIVE_NO_ROOT_DIR: |
+ type_str = "unmounted"; |
+ case DRIVE_REMOVABLE: |
+ type_str = "removable"; |
+ break; |
+ case DRIVE_FIXED: |
+ type_str = "fixed"; |
+ break; |
+ case DRIVE_REMOTE: |
+ type_str = "remote"; |
+ break; |
+ case DRIVE_CDROM: |
+ type_str = "cdrom"; |
+ break; |
+ case DRIVE_RAMDISK: |
+ type_str = "ramdisk"; |
+ break; |
+ default: |
+ type_str = "?"; |
+ break; |
+ } |
+ |
+ return Py_BuildValue("s", type_str); |
+} |
+ |
+ |
+// ------------------------ Python init --------------------------- |
+ |
+static PyMethodDef |
+PsutilMethods[] = |
+{ |
+ // --- per-process functions |
+ |
+ {"get_process_name", get_process_name, METH_VARARGS, |
+ "Return process name"}, |
+ {"get_process_cmdline", get_process_cmdline, METH_VARARGS, |
+ "Return process cmdline as a list of cmdline arguments"}, |
+ {"get_process_ppid", get_process_ppid, METH_VARARGS, |
+ "Return process ppid as an integer"}, |
+ {"kill_process", kill_process, METH_VARARGS, |
+ "Kill the process identified by the given PID"}, |
+ {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, |
+ "Return tuple of user/kern time for the given PID"}, |
+ {"get_process_create_time", get_process_create_time, METH_VARARGS, |
+ "Return a float indicating the process create time expressed in " |
+ "seconds since the epoch"}, |
+ {"get_memory_info", get_memory_info, METH_VARARGS, |
+ "Return a tuple of RSS/VMS memory information"}, |
+ {"get_process_cwd", get_process_cwd, METH_VARARGS, |
+ "Return process current working directory"}, |
+ {"suspend_process", suspend_process, METH_VARARGS, |
+ "Suspend a process"}, |
+ {"resume_process", resume_process, METH_VARARGS, |
+ "Resume a process"}, |
+ {"get_process_open_files", get_process_open_files, METH_VARARGS, |
+ "Return files opened by process"}, |
+ {"get_process_username", get_process_username, METH_VARARGS, |
+ "Return the username of a process"}, |
+ {"get_process_connections", get_process_connections, METH_VARARGS, |
+ "Return the network connections of a process"}, |
+ {"get_process_num_threads", get_process_num_threads, METH_VARARGS, |
+ "Return the network connections of a process"}, |
+ {"get_process_threads", get_process_threads, METH_VARARGS, |
+ "Return process threads information as a list of tuple"}, |
+ {"process_wait", process_wait, METH_VARARGS, |
+ "Wait for process to terminate and return its exit code."}, |
+ {"get_process_priority", get_process_priority, METH_VARARGS, |
+ "Return process priority."}, |
+ {"set_process_priority", set_process_priority, METH_VARARGS, |
+ "Set process priority."}, |
+ {"get_process_io_counters", get_process_io_counters, METH_VARARGS, |
+ "Get process I/O counters."}, |
+ {"is_process_suspended", is_process_suspended, METH_VARARGS, |
+ "Return True if one of the process threads is in a suspended state"}, |
+ |
+ // --- system-related functions |
+ |
+ {"get_pid_list", get_pid_list, METH_VARARGS, |
+ "Returns a list of PIDs currently running on the system"}, |
+ {"pid_exists", pid_exists, METH_VARARGS, |
+ "Determine if the process exists in the current process list."}, |
+ {"get_num_cpus", get_num_cpus, METH_VARARGS, |
+ "Returns the number of CPUs on the system"}, |
+ {"get_system_uptime", get_system_uptime, METH_VARARGS, |
+ "Return system uptime"}, |
+ {"get_system_phymem", get_system_phymem, METH_VARARGS, |
+ "Return the total amount of physical memory, in bytes"}, |
+ {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, |
+ "Return system per-cpu times as a list of tuples"}, |
+ {"get_disk_usage", get_disk_usage, METH_VARARGS, |
+ "Return path's disk total and free as a Python tuple."}, |
+ |
+ // --- windows API bindings |
+ {"win32_GetLogicalDriveStrings", win32_GetLogicalDriveStrings, METH_VARARGS, |
+ "GetLogicalDriveStrings binding"}, |
+ {"win32_GetDriveType", win32_GetDriveType, METH_VARARGS, |
+ "GetDriveType binding"}, |
+ {"win32_QueryDosDevice", win32_QueryDosDevice, METH_VARARGS, |
+ "QueryDosDevice binding"}, |
+ |
+ {NULL, NULL, 0, NULL} |
+}; |
+ |
+ |
+struct module_state { |
+ PyObject *error; |
+}; |
+ |
+#if PY_MAJOR_VERSION >= 3 |
+ #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) |
+#else |
+ #define GETSTATE(m) (&_state) |
+ static struct module_state _state; |
+#endif |
+ |
+#if PY_MAJOR_VERSION >= 3 |
+ |
+ static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) { |
+ Py_VISIT(GETSTATE(m)->error); |
+ return 0; |
+ } |
+ |
+ static int psutil_mswindows_clear(PyObject *m) { |
+ Py_CLEAR(GETSTATE(m)->error); |
+ return 0; |
+ } |
+ |
+ static struct PyModuleDef moduledef = { |
+ PyModuleDef_HEAD_INIT, |
+ "psutil_mswindows", |
+ NULL, |
+ sizeof(struct module_state), |
+ PsutilMethods, |
+ NULL, |
+ psutil_mswindows_traverse, |
+ psutil_mswindows_clear, |
+ NULL |
+ }; |
+ |
+#define INITERROR return NULL |
+ |
+ PyObject* PyInit__psutil_mswindows(void) |
+ |
+#else |
+ #define INITERROR return |
+ void init_psutil_mswindows(void) |
+#endif |
+{ |
+ struct module_state *st = NULL; |
+#if PY_MAJOR_VERSION >= 3 |
+ PyObject *module = PyModule_Create(&moduledef); |
+#else |
+ PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods); |
+#endif |
+ |
+ if (module == NULL) { |
+ INITERROR; |
+ } |
+ |
+ st = GETSTATE(module); |
+ st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL); |
+ if (st->error == NULL) { |
+ Py_DECREF(module); |
+ INITERROR; |
+ } |
+ |
+ // Public constants |
+ // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx |
+ PyModule_AddIntConstant(module, "ABOVE_NORMAL_PRIORITY_CLASS", |
+ ABOVE_NORMAL_PRIORITY_CLASS); |
+ PyModule_AddIntConstant(module, "BELOW_NORMAL_PRIORITY_CLASS", |
+ BELOW_NORMAL_PRIORITY_CLASS); |
+ PyModule_AddIntConstant(module, "HIGH_PRIORITY_CLASS", |
+ HIGH_PRIORITY_CLASS); |
+ PyModule_AddIntConstant(module, "IDLE_PRIORITY_CLASS", |
+ IDLE_PRIORITY_CLASS); |
+ PyModule_AddIntConstant(module, "NORMAL_PRIORITY_CLASS", |
+ NORMAL_PRIORITY_CLASS); |
+ PyModule_AddIntConstant(module, "REALTIME_PRIORITY_CLASS", |
+ REALTIME_PRIORITY_CLASS); |
+ // private constants |
+ PyModule_AddIntConstant(module, "INFINITE", INFINITE); |
+ SetSeDebug(); |
+ |
+#if PY_MAJOR_VERSION >= 3 |
+ return module; |
+#endif |
+} |
+ |
+ |
+ |