From 762b37dba0309b5eb1d355da3869be596a145caa Mon Sep 17 00:00:00 2001 From: Peter Eastham Date: Thu, 4 Aug 2022 17:44:39 -0600 Subject: [PATCH] Code Review and Build Errors Fix. --- .../src/com/sun/jna/platform/win32/Psapi.java | 106 ++++++++++++++++++ .../com/sun/jna/platform/win32/PsapiTest.java | 42 +++++++ 2 files changed, 148 insertions(+) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java b/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java index dfd13d204d..31abe99896 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java @@ -28,6 +28,7 @@ import com.sun.jna.Structure; import com.sun.jna.Structure.FieldOrder; import com.sun.jna.platform.win32.BaseTSD.SIZE_T; +import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR; import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinDef.HMODULE; import com.sun.jna.platform.win32.WinNT.HANDLE; @@ -292,6 +293,18 @@ public interface Psapi extends StdCallLibrary { */ boolean EnumProcesses(int[] lpidProcess, int cb, IntByReference lpcbNeeded); + /** + * Retrieves extended information about the pages at specific + * virtual addresses in the address space of the specified process. + * + * @param hProcess A Handle to the Process + * @param pv A pointer to an array of PSAPI_WORKING_SET_EX_INFORMATION structures + * @param cb The size of the pv buffer, in bytes. + * @return If the function succeeds, the return value is nonzero. + * @see MSDN + */ + boolean QueryWorkingSetEx(HANDLE hProcess, PSAPI_WORKING_SET_EX_INFORMATION pv, DWORD cb); + @FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"}) class MODULEINFO extends Structure { public Pointer EntryPoint; @@ -320,4 +333,97 @@ class PERFORMANCE_INFORMATION extends Structure { public DWORD ProcessCount; public DWORD ThreadCount; } + + @FieldOrder({"Flags", "Data"}) + class PSAPI_WORKING_SET_EX_BLOCK extends Structure { + public ULONG_PTR Flags; + public ULONG[] Data = new ULONG[Native.POINTER_SIZE == 8 ? 1 : 2]; + private long innerValue; + + @Override + public void read() { + super.read(); + innerValue = this.Data[0].longValue(); + } + + /** + * If this bit is 1, the subsequent members are valid; otherwise they should be ignored. + */ + public boolean Valid() { + return getBitFieldValue(1, 0) == 1; + } + + /** + * The number of processes that share this page. The maximum value of this member is 7. + */ + public int ShareCount() { + return getBitFieldValue(3, 1); + } + + /** + * The memory protection attributes of the page. For a list of values see below. + * @see Memory Protection Constants. + */ + public int Win32Protection() { + return getBitFieldValue(11, 3 + 1); + } + + /** + * If this bit is 1, the page can be shared. + */ + public boolean Shared() { + return getBitFieldValue(1, 11 + 3 + 1) == 1; + } + + /** + * The NUMA node. The maximum value of this member is 63. + */ + public int Node() { + return getBitFieldValue(6, 1 + 11 + 3 + 1); + } + + /** + * If this bit is 1, the virtual page is locked in physical memory. + */ + public boolean Locked() { + return getBitFieldValue(1, 6 + 1 + 11 + 3 + 1) == 1; + } + + /** + * If this bit is 1, the page is a large page. + */ + public boolean LargePage() { + return getBitFieldValue(1, 1 + 6 + 1 + 11 + 3 + 1) == 1; + } + + /** + * If this bit is 1, the page is has been reported as bad. + */ + public boolean Bad() { + return getBitFieldValue(1,1 + 1 + 1 + 6 + 1 + 11 + 3 + 1) == 1; + } + + /** + * Returns innerValue after shifting the value rightShiftAmount, and applying a Bit Mask of size maskLength. Example,
+ * innerValue = 0011
getBitFieldValue(2, 1) = 0011 >> 1 & 11 = 01 + * @param maskLength Size of the Bit Mask + * @param rightShiftAmount Amount to Shift innerValue to the right by + * @return innerValue with the mask and shift applied. + */ + private int getBitFieldValue(final int maskLength, final int rightShiftAmount) { + long bitMask = 0; + + for (int l = 0; l <= maskLength - rightShiftAmount; l++) { + bitMask |= 1 << l; + } + return (int) ((innerValue >> rightShiftAmount) & bitMask); + } + } + + + @FieldOrder({"VirtualAddress", "VirtualAttributes"}) + class PSAPI_WORKING_SET_EX_INFORMATION extends Structure { + public Pointer VirtualAddress; + public PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes; + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java index 7af0c9b275..6f4dd674f8 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java @@ -24,6 +24,7 @@ package com.sun.jna.platform.win32; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import java.util.LinkedList; import java.util.List; @@ -34,12 +35,15 @@ import com.sun.jna.Memory; import com.sun.jna.Native; +import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Psapi.MODULEINFO; import com.sun.jna.platform.win32.Psapi.PERFORMANCE_INFORMATION; import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinDef.HMODULE; import com.sun.jna.platform.win32.WinDef.HWND; import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION; +import com.sun.jna.platform.win32.BaseTSD.SIZE_T; import com.sun.jna.ptr.IntByReference; /** @@ -273,4 +277,42 @@ public void testEnumProcesses() { } assertTrue("List should contain my pid", foundMyPid); } + + @Test + public void testQueryWorkingSetEx() { + Win32Exception we = null; + HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess(); + MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); + try { + SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size())); + assertTrue("It should read correctly", bytesRead.intValue() != 0); + Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION(); + pswsi.VirtualAddress = mbi.baseAddress; + if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi, new DWORD(pswsi.size()))) { + throw new Win32Exception(Native.getLastError()); + } + assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null); + if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi, new DWORD(pswsi.size()))) { + throw new Win32Exception(Native.getLastError()); + } + assertFalse("This line should never be called", true); + } catch (Win32Exception e) { + we = e; + throw we; // re-throw to invoke finally block + } finally { + try { + Kernel32Util.closeHandle(selfHandle); + } catch (Win32Exception e) { + if (we == null) { + we = e; + } else { + we.addSuppressedReflected(e); + } + } + if (we != null) { + throw we; + } + } + } } +