diff --git a/CHANGES.md b/CHANGES.md index d8a80ce078..041326a905 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,8 @@ 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). +* [#1459](https://github.com/java-native-access/jna/pull/1459): Add `VirtualLock` and `VirtualUnlock` in `c.s.j.p.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java index 947beb396e..14a1bd772b 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -4307,4 +4307,84 @@ Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, * @see MSDN Entry */ HRESULT GetApplicationRestartSettings(HANDLE hProcess, char[] pwzCommandline, IntByReference pcchSize, IntByReference pdwFlags); + + /** + * Locks the specified region of the process's virtual address space into + * physical memory, ensuring that subsequent access to the region will not + * incur a page fault. + * + * @param lpAddress A pointer to the base address of the region of pages to + * be locked. + * @param dwSize The size of the region to be locked, in bytes. The + * region of affected pages includes all pages that contain + * one or more bytes in the range from the lpAddress + * parameter to (lpAddress+dwSize). This means that a + * 2-byte range straddling a page boundary causes both + * pages to be locked. + * + * @return {@code true} if locking succeeded. + * + *
+ * All pages in the specified region must be committed. Memory protected + * with {@code PAGE_NOACCESS} cannot be locked. + *
+ *+ * Locking pages into memory may degrade the performance of the system by + * reducing the available RAM and forcing the system to swap out other + * critical pages to the paging file. Each version of Windows has a limit on + * the maximum number of pages a process can lock. This limit is + * intentionally small to avoid severe performance degradation. Applications + * that need to lock larger numbers of pages must first call the + * SetProcessWorkingSetSize function to increase their minimum and maximum + * working set sizes. The maximum number of pages that a process can lock is + * equal to the number of pages in its minimum working set minus a small + * overhead. + *
+ *+ * Pages that a process has locked remain in physical memory until the + * process unlocks them or terminates. These pages are guaranteed not to be + * written to the pagefile while they are locked. + *
+ *+ * To unlock a region of locked pages, use the VirtualUnlock function. + * Locked pages are automatically unlocked when the process terminates. + *
+ *+ * This function is not like the GlobalLock or LocalLock function in that it + * does not increment a lock count and translate a handle into a pointer. + * There is no lock count for virtual pages, so multiple calls to the + * VirtualUnlock function are never required to unlock a region of pages. + *
+ */ + boolean VirtualLock(Pointer lpAddress, SIZE_T dwSize); + + /** + * Unlocks a specified range of pages in the virtual address space of a + * process, enabling the system to swap the pages out to the paging file if + * necessary. + * + * @param lpAddress A pointer to the base address of the region of pages to + * be unlocked. + * @param dwSize The size of the region being unlocked, in bytes. The + * region of affected pages includes all pages containing + * one or more bytes in the range from the lpAddress + * parameter to (lpAddress+dwSize). This means that a + * 2-byte range straddling a page boundary causes both + * pages to be unlocked. + * + * @return {@code true} if unlocking succeeded. + * + *+ * For the function to succeed, the range specified need not match a range + * passed to a previous call to the VirtualLock function, but all pages in + * the range must be locked. If any of the pages in the specified range are + * not locked, VirtualUnlock removes such pages from the working set, sets + * last error to ERROR_NOT_LOCKED, and returns FALSE. + *
+ *+ * Calling VirtualUnlock on a range of memory that is not locked releases + * the pages from the process's working set. + *
+ */ + boolean VirtualUnlock(Pointer lpAddress, SIZE_T dwSize); } 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..e5b99d4bbc 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java @@ -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; @@ -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 MSDN + */ + boolean QueryWorkingSetEx(HANDLE hProcess, Pointer pv, int cb); + @FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"}) class MODULEINFO extends Structure { public Pointer EntryPoint; @@ -320,4 +334,92 @@ class PERFORMANCE_INFORMATION extends Structure { public DWORD ProcessCount; public DWORD ThreadCount; } + + @FieldOrder({"VirtualAddress", "VirtualAttributes"}) + class PSAPI_WORKING_SET_EX_INFORMATION extends Structure { + + public Pointer VirtualAddress; + public ULONG_PTR VirtualAttributes; + + /** + * 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 + * Memory + * Protection Constants. + */ + 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,