Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added QueryWorkingSetEx to PSAPI #1454

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Next Release (5.13.0)

Features
--------
* [#1454](https://github.com/java-native-access/jna/pull/1454): Add `c.s.j.p.win32.Psapi.QueryWorkingSetEx` and associated Types - [@crain-32](https://github.com/Crain-32).

Bug Fixes
---------
Expand Down
116 changes: 116 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Structure.ByReference;
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;
Expand Down Expand Up @@ -292,6 +294,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 <a href="https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex">MSDN</a>
*/
boolean QueryWorkingSetEx(HANDLE hProcess, Pointer pv, int cb);

@FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"})
class MODULEINFO extends Structure {
public Pointer EntryPoint;
Expand Down Expand Up @@ -320,4 +334,106 @@ class PERFORMANCE_INFORMATION extends Structure {
public DWORD ProcessCount;
public DWORD ThreadCount;
}

@FieldOrder({"Flags", "Data"})
class PSAPI_WORKING_SET_EX_BLOCK extends Structure implements ByReference {
public ULONG_PTR Flags;
public ULONG_PTR[] Data = new ULONG_PTR[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 isValid() {
return getBitFieldValue(1, 0) == 1;
}

/**
* The number of processes that share this page. The maximum value of this
* member is 7.
*/
public int getShareCount() {
return getBitFieldValue(3, 1);
}

/**
* The memory protection attributes of the page. For a list of values see below.
*
* @see <a href=
* "https://docs.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants">Memory
* Protection Constants</a>.
*/
public int getWin32Protection() {
return getBitFieldValue(11, 3 + 1);
}

/**
* If this bit is 1, the page can be shared.
*/
public boolean isShared() {
return getBitFieldValue(1, 11 + 3 + 1) == 1;
}

/**
* The NUMA node. The maximum value of this member is 63.
*/
public int getNode() {
return getBitFieldValue(6, 1 + 11 + 3 + 1);
}

/**
* If this bit is 1, the virtual page is locked in physical memory.
*/
public boolean isLocked() {
return getBitFieldValue(1, 6 + 1 + 11 + 3 + 1) == 1;
}

/**
* If this bit is 1, the page is a large page.
*/
public boolean isLargePage() {
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 isBad() {
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, <br/>
* innerValue = 0011<br/>
* 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 bit = 0; bit < maskLength; bit++) {
bitMask |= 1 << bit;
}
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;
}
}
42 changes: 42 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
*/
package com.sun.jna.platform.win32;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

import java.util.LinkedList;
Expand All @@ -34,12 +36,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;

/**
Expand Down Expand Up @@ -273,4 +278,41 @@ 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()));
assertNotEquals("Kernel should be able to read this Process' Bytes", 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.VirtualAddress, pswsi.size())) {
throw new Win32Exception(Native.getLastError());
}
assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi.VirtualAddress, 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;
}
}
}
}