Skip to content

Commit 4ce1914

Browse files
committed
Added c.s.j.win32.Psapi.QueryWorkingSetEx
1 parent 999c60a commit 4ce1914

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Next Release (5.13.0)
77

88
Features
99
--------
10+
* [#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).
1011

1112
Bug Fixes
1213
---------

contrib/platform/src/com/sun/jna/platform/win32/Psapi.java

+27
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import com.sun.jna.Native;
2727
import com.sun.jna.Pointer;
2828
import com.sun.jna.Structure;
29+
import com.sun.jna.Structure.ByReference;
2930
import com.sun.jna.Structure.FieldOrder;
3031
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
32+
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
3133
import com.sun.jna.platform.win32.WinDef.DWORD;
3234
import com.sun.jna.platform.win32.WinDef.HMODULE;
3335
import com.sun.jna.platform.win32.WinNT.HANDLE;
@@ -292,6 +294,18 @@ public interface Psapi extends StdCallLibrary {
292294
*/
293295
boolean EnumProcesses(int[] lpidProcess, int cb, IntByReference lpcbNeeded);
294296

297+
/**
298+
* Retrieves extended information about the pages at specific
299+
* virtual addresses in the address space of the specified process.
300+
*
301+
* @param hProcess A Handle to the Process
302+
* @param pv A pointer to an array of PSAPI_WORKING_SET_EX_INFORMATION structures
303+
* @param cb The size of the pv buffer, in bytes.
304+
* @return If the function succeeds, the return value is nonzero.
305+
* @see <a href="https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex">MSDN</a>
306+
*/
307+
boolean QueryWorkingSetEx(HANDLE hProcess, Pointer pv, int cb);
308+
295309
@FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"})
296310
class MODULEINFO extends Structure {
297311
public Pointer EntryPoint;
@@ -320,4 +334,17 @@ class PERFORMANCE_INFORMATION extends Structure {
320334
public DWORD ProcessCount;
321335
public DWORD ThreadCount;
322336
}
337+
338+
@FieldOrder({"Flags", "Data"})
339+
class PSAPI_WORKING_SET_EX_BLOCK extends Structure implements ByReference {
340+
public ULONG_PTR Flags;
341+
public ULONG_PTR[] Data = new ULONG_PTR[Native.POINTER_SIZE == 8 ? 1 : 2];
342+
}
343+
344+
345+
@FieldOrder({"VirtualAddress", "VirtualAttributes"})
346+
class PSAPI_WORKING_SET_EX_INFORMATION extends Structure {
347+
public Pointer VirtualAddress;
348+
public PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes;
349+
}
323350
}

contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java

+76
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import com.sun.jna.platform.win32.WinDef.DWORD;
3030
import com.sun.jna.platform.win32.WinNT.HANDLE;
31+
import com.sun.jna.platform.win32.Psapi.PSAPI_WORKING_SET_EX_BLOCK;
3132
import com.sun.jna.ptr.IntByReference;
3233

3334
/**
@@ -87,4 +88,79 @@ public static String GetProcessImageFileName(HANDLE hProcess) {
8788
}
8889
}
8990
}
91+
92+
@Override
93+
public void read() {
94+
super.read();
95+
innerValue = this.Data[0].longValue();
96+
}
97+
98+
/**
99+
* If this bit is 1, the other values in the PSAPI_WORKING_SET_EX_BLOCK are valid.
100+
*/
101+
public static boolean isPsapiWorkingSetExBlockValid(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
102+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 1, 0) == 1;
103+
}
104+
105+
/**
106+
* The number of processes that share the page addressed by the PSAPI_WORKING_SET_EX_BLOCK. The maximum value of this member is 7.
107+
*/
108+
public static int getPsapiWorkingSetExBlockShareCount(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
109+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 3, 1);
110+
}
111+
112+
/**
113+
* The memory protection attributes of the page addressed by the PSAPI_WORKING_SET_EX_BLOCK. For a list of values see below.
114+
* @see <a href="https://docs.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants">Memory Protection Constants</a>.
115+
*/
116+
public static int getPsapiWorkingSetExBlockWin32Protection(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
117+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(),11, 3 + 1);
118+
}
119+
120+
/**
121+
* If this bit is 1, the page addressed by the PSAPI_WORKING_SET_EX_BLOCK can be shared.
122+
*/
123+
public static boolean isPsapiWorkingSetExBlockShared(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
124+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 1, 11 + 3 + 1) == 1;
125+
}
126+
127+
/**
128+
* The NUMA node of the page addressed by the PSAPI_WORKING_SET_EX_BLOCK. The maximum value of this member is 63.
129+
*/
130+
public static int getPsapiWorkingSetExBlockNode(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
131+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 6, 1 + 11 + 3 + 1);
132+
}
133+
134+
/**
135+
* If this bit is 1, the virtual page addressed by the PSAPI_WORKING_SET_EX_BLOCK is locked in physical memory.
136+
*/
137+
public static boolean isPsapiWorkingSetExBlockLocked(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
138+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 1, 6 + 1 + 11 + 3 + 1) == 1;
139+
}
140+
141+
/**
142+
* If this bit is 1, the page addressed by the PSAPI_WORKING_SET_EX_BLOCK is a large page.
143+
*/
144+
public static boolean isPsapiWorkingSetExBlockLargePage(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
145+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(),1, 1 + 6 + 1 + 11 + 3 + 1) == 1;
146+
}
147+
148+
/**
149+
* If this bit is 1, the page addressed by the PSAPI_WORKING_SET_EX_BLOCK is has been reported as bad.
150+
*/
151+
public static boolean isPsapiWorkingSetExBlockBad(PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock) {
152+
return PsapiUtil.getBitFieldValue(psapiWorkingSetExBlock.Data[0].longValue(), 1,1 + 1 + 1 + 6 + 1 + 11 + 3 + 1) == 1;
153+
}
154+
155+
/**
156+
* Returns a Right Shifted and Masked version of value.
157+
*/
158+
public static int getBitFieldValue(final int value, final int maskLength, final int rightShiftAmount) {
159+
long bitMask = 0;
160+
161+
for (int l = 0; l < maskLength; l++) {
162+
bitMask |= 1 << l;
163+
}
164+
return (int) ((value >>> rightShiftAmount) & bitMask);
165+
}
90166
}

contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java

+43
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
package com.sun.jna.platform.win32;
2525

2626
import static org.junit.Assert.assertTrue;
27+
import static org.junit.Assert.assertNotEquals;
28+
import static org.junit.Assert.assertFalse;
2729

2830
import java.util.LinkedList;
2931
import java.util.List;
@@ -34,12 +36,15 @@
3436

3537
import com.sun.jna.Memory;
3638
import com.sun.jna.Native;
39+
import com.sun.jna.Pointer;
3740
import com.sun.jna.platform.win32.Psapi.MODULEINFO;
3841
import com.sun.jna.platform.win32.Psapi.PERFORMANCE_INFORMATION;
3942
import com.sun.jna.platform.win32.WinDef.DWORD;
4043
import com.sun.jna.platform.win32.WinDef.HMODULE;
4144
import com.sun.jna.platform.win32.WinDef.HWND;
4245
import com.sun.jna.platform.win32.WinNT.HANDLE;
46+
import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
47+
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
4348
import com.sun.jna.ptr.IntByReference;
4449

4550
/**
@@ -273,4 +278,42 @@ public void testEnumProcesses() {
273278
}
274279
assertTrue("List should contain my pid", foundMyPid);
275280
}
281+
282+
@Test
283+
public void testQueryWorkingSetEx() {
284+
Win32Exception we = null;
285+
HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess();
286+
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
287+
try {
288+
SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size()));
289+
assertNotEquals("Kernel should be able to read this Process' Bytes", bytesRead.intValue(), 0);
290+
Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION();
291+
pswsi.VirtualAddress = mbi.baseAddress;
292+
if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi.VirtualAddress, pswsi.size())) {
293+
throw new Win32Exception(Native.getLastError());
294+
}
295+
assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
296+
if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi.VirtualAddress, pswsi.size())) {
297+
throw new Win32Exception(Native.getLastError());
298+
}
299+
assertFalse("This line should never be called", true);
300+
} catch (Win32Exception e) {
301+
we = e;
302+
throw we; // re-throw to invoke finally block
303+
} finally {
304+
try {
305+
Kernel32Util.closeHandle(selfHandle);
306+
} catch (Win32Exception e) {
307+
if (we == null) {
308+
we = e;
309+
} else {
310+
we.addSuppressedReflected(e);
311+
}
312+
}
313+
if (we != null) {
314+
throw we;
315+
}
316+
}
317+
}
276318
}
319+

contrib/platform/test/com/sun/jna/platform/win32/PsapiUtilTest.java

+47
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525

2626
import static org.junit.Assert.assertNotNull;
2727
import static org.junit.Assert.assertTrue;
28+
import static org.junit.Assert.assertNotEquals;
29+
30+
31+
import com.sun.jna.Pointer;
32+
import com.sun.jna.platform.win32.Psapi.MODULEINFO;
33+
import com.sun.jna.platform.win32.Psapi.PERFORMANCE_INFORMATION;
34+
import com.sun.jna.platform.win32.WinDef.DWORD;
35+
import com.sun.jna.platform.win32.WinDef.HMODULE;
36+
import com.sun.jna.platform.win32.WinDef.HWND;
37+
import com.sun.jna.platform.win32.WinNT.HANDLE;
38+
import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
39+
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
2840

2941
import org.junit.Test;
3042

@@ -50,4 +62,39 @@ public void enumProcesses() {
5062
}
5163
assertTrue("List should contain my pid", foundMyPid);
5264
}
65+
66+
@Test
67+
public void testPsapiWorkingSetExBlockUtils() {
68+
Win32Exception we = null;
69+
HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess();
70+
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
71+
try {
72+
SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size()));
73+
assertNotEquals("Kernel should be able to read this Process' Bytes", bytesRead.intValue(), 0);
74+
Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION();
75+
pswsi.VirtualAddress = mbi.baseAddress;
76+
if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi.VirtualAddress, pswsi.size())) {
77+
throw new Win32Exception(Native.getLastError());
78+
}
79+
assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
80+
PSAPI_WORKING_SET_EX_BLOCK psapiWorkingSetExBlock = pswsi.VirtualAttributes;
81+
assertTrue("The JVM Page should be valid", PsapiUtil.isPsapiWorkingSetExBlockValid(psapiWorkingSetExBlock));
82+
} catch (Win32Exception e) {
83+
we = e;
84+
throw we; // re-throw to invoke finally block
85+
} finally {
86+
try {
87+
Kernel32Util.closeHandle(selfHandle);
88+
} catch (Win32Exception e) {
89+
if (we == null) {
90+
we = e;
91+
} else {
92+
we.addSuppressedReflected(e);
93+
}
94+
}
95+
if (we != null) {
96+
throw we;
97+
}
98+
}
99+
}
53100
}

0 commit comments

Comments
 (0)