From 70469d428dd94693295b320a975b1ddf904dda3b Mon Sep 17 00:00:00 2001 From: xEgoist Date: Wed, 22 Mar 2023 05:57:14 -0500 Subject: [PATCH] Implemented Zig wrapper for `GetProcessMemoryInfo` `GetProcessMemoryInfo` is implemented using `NtQueryInformationProcess` with `ProcessVmCounters` to obtain `VM_COUNTERS`. The structs, enum definitions are found in `winternl.h` or `ntddk.h` in the latest WDK. This should give the same results as using `K32GetProcessMemoryInfo` --- lib/std/child_process.zig | 6 ++-- lib/std/os/windows.zig | 45 ++++++++++++++++++++++++++ lib/std/os/windows/ntdll.zig | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 72d7be4451..13fd40d982 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -137,6 +137,7 @@ pub const ChildProcess = struct { os.SetIdError || os.ChangeCurDirError || windows.CreateProcessError || + windows.GetProcessMemoryInfoError || windows.WaitForSingleObjectError; pub const Term = union(enum) { @@ -374,9 +375,8 @@ pub const ChildProcess = struct { if (self.request_resource_usage_statistics) { var pmc: windows.PROCESS_MEMORY_COUNTERS = undefined; - if (windows.kernel32.K32GetProcessMemoryInfo(self.id, &pmc, @sizeOf(windows.PROCESS_MEMORY_COUNTERS)) != 0) { - self.resource_usage_statistics.rusage = pmc; - } + try windows.GetProcessMemoryInfo(self.id, &pmc); + self.resource_usage_statistics.rusage = pmc; } os.close(self.id); diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index b385f68194..27f2ddb316 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -3947,6 +3947,20 @@ pub const PSAPI_WS_WATCH_INFORMATION = extern struct { FaultingVa: LPVOID, }; +pub const VM_COUNTERS = extern struct { + PeakVirtualSize: SIZE_T, + VirtualSize: SIZE_T, + PageFaultCount: ULONG, + PeakWorkingSetSize: SIZE_T, + WorkingSetSize: SIZE_T, + QuotaPeakPagedPoolUsage: SIZE_T, + QuotaPagedPoolUsage: SIZE_T, + QuotaPeakNonPagedPoolUsage: SIZE_T, + QuotaNonPagedPoolUsage: SIZE_T, + PagefileUsage: SIZE_T, + PeakPagefileUsage: SIZE_T, +}; + pub const PROCESS_MEMORY_COUNTERS = extern struct { cb: DWORD, PageFaultCount: DWORD, @@ -3974,6 +3988,37 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct { PrivateUsage: SIZE_T, }; +pub const GetProcessMemoryInfoError = error{ + AccessDenied, + InvalidHandle, + Unexpected, +}; + +pub fn GetProcessMemoryInfo(hProcess: HANDLE, out: *PROCESS_MEMORY_COUNTERS) GetProcessMemoryInfoError!void { + var vmc: VM_COUNTERS = undefined; + const rc = ntdll.NtQueryInformationProcess(hProcess, .ProcessVmCounters, &vmc, @sizeOf(VM_COUNTERS), null); + switch (rc) { + .SUCCESS => { + out.* = PROCESS_MEMORY_COUNTERS{ + .cb = @sizeOf(PROCESS_MEMORY_COUNTERS), + .PageFaultCount = vmc.PageFaultCount, + .PeakWorkingSetSize = vmc.PeakWorkingSetSize, + .WorkingSetSize = vmc.WorkingSetSize, + .QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage, + .QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage, + .QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage, + .QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage, + .PagefileUsage = vmc.PagefileUsage, + .PeakPagefileUsage = vmc.PeakPagefileUsage, + }; + }, + .ACCESS_DENIED => return error.AccessDenied, + .INVALID_HANDLE => return error.InvalidHandle, + .INVALID_PARAMETER => unreachable, + else => return unexpectedStatus(rc), + } +} + pub const PERFORMANCE_INFORMATION = extern struct { cb: DWORD, CommitTotal: SIZE_T, diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 58cba356a2..3916e7d178 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -32,6 +32,69 @@ const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION; const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS; const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE; +pub const PROCESSINFOCLASS = enum(c_int) { + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessTlsInformation, + ProcessCookie, + ProcessImageInformation, + ProcessCycleTime, + ProcessPagePriority, + ProcessInstrumentationCallback, + ProcessThreadStackAllocation, + ProcessWorkingSetWatchEx, + ProcessImageFileNameWin32, + ProcessImageFileMapping, + ProcessAffinityUpdateMode, + ProcessMemoryAllocationMode, + ProcessGroupInformation, + ProcessTokenVirtualizationEnabled, + ProcessConsoleHostProcess, + ProcessWindowInformation, + MaxProcessInfoClass +}; + +pub extern "ntdll" fn NtQueryInformationProcess( + ProcessHandle: HANDLE, + ProcessInformationClass: PROCESSINFOCLASS, + ProcessInformation: *anyopaque, + ProcessInformationLength: ULONG, + ReturnLength: ?*ULONG, +) callconv(WINAPI) NTSTATUS; + pub const THREADINFOCLASS = enum(c_int) { ThreadBasicInformation, ThreadTimes,