diff --git a/CHANGES.md b/CHANGES.md index 4ab7bcb770..374d2c9642 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,10 +10,12 @@ Features * [#1058](https://github.com/java-native-access/jna/pull/1058): Add selectable timeout to stopService() and improve timeout handling - [@keithharp](https://github.com/keithharp). * [#1050](https://github.com/java-native-access/jna/pull/1050): Add `c.s.j.p.win32.VersionHelpers` and supporting functions - [@dbwiddis](https://github.com/dbwiddis). * [#1061](https://github.com/java-native-access/jna/pull/1061): replace toArray(new T[size]) with toArray(new T[0]) for better performance - [@hc-codersatlas](https://github.com/hc-codersatlas). +* [#1064](https://github.com/java-native-access/jna/pull/1064): Add `c.s.j.p.win32.Kernel32.GetLogicalProcessorInformationEx` function, convenience Util method and supporting structures - [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- -* [#1052](https://github.com/java-native-access/jna/issues/1052), [#1053](https://github.com/java-native-access/jna/issues/1053): WinXP compatibility for `c.s.j.p.win32.PdhUtil` - [@dbwiddis](https://github.com/dbwiddis). +* [#1052](https://github.com/java-native-access/jna/pull/1052), [#1053](https://github.com/java-native-access/jna/issues/1053): WinXP compatibility for `c.s.j.p.win32.PdhUtil` - [@dbwiddis](https://github.com/dbwiddis). +* [#1055](https://github.com/java-native-access/jna/pull/1055): Include `c.s.j.p.linux` in OSGi bundle. - [@dbwiddis](https://github.com/dbwiddis). Release 5.2.0 ============= 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 e012b1349e..4043616531 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -24,6 +24,7 @@ package com.sun.jna.platform.win32; import com.sun.jna.LastErrorException; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; @@ -1534,6 +1535,45 @@ boolean CreateProcessW(String lpApplicationName, char[] lpCommandLine, boolean GetLogicalProcessorInformation(Pointer buffer, DWORDByReference returnLength); + /** + * Retrieves information about the relationships of logical processors and + * related hardware. + * + * @param relationshipType + * The type of relationship to retrieve. This parameter can be + * one of the following values: + * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationCache}, + * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationGroup}, + * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationNumaNode}, + * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore}, + * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage}, + * or {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationAll} + * @param buffer + * A pointer to a buffer that receives an array of + * {@link WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} + * structures. If the function fails, the contents of this buffer + * are undefined. + * @param returnedLength + * On input, specifies the length of the buffer pointed to by + * Buffer, in bytes. If the buffer is large enough to contain all + * of the data, this function succeeds and ReturnedLength is set + * to the number of bytes returned. If the buffer is not large + * enough to contain all of the data, the function fails, + * GetLastError returns + * {@link WinError#ERROR_INSUFFICIENT_BUFFER}, and ReturnedLength + * is set to the buffer length required to contain all of the + * data. If the function fails with an error other than + * {@link WinError#ERROR_INSUFFICIENT_BUFFER}, the value of + * ReturnedLength is undefined. + * @return If the function succeeds, the return value is {@code TRUE} and at + * least one {@link WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} + * structure is written to the output buffer. + *
+ * If the function fails, the return value is {@code FALSE}. To get
+ * extended error information, call {@link #GetLastError()}.
+ */
+ boolean GetLogicalProcessorInformationEx(int relationshipType, Pointer buffer, DWORDByReference returnedLength);
+
/**
* Retrieves information about the system's current usage of both physical
* and virtual memory.
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
index 991e60be2c..a04e0854d3 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
@@ -39,6 +39,8 @@
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.WinNT.HRESULT;
+import com.sun.jna.platform.win32.WinNT.LOGICAL_PROCESSOR_RELATIONSHIP;
+import com.sun.jna.platform.win32.WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.W32APITypeMapper;
@@ -671,12 +673,52 @@ public static final WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] getLogicalProce
}
WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION firstInformation = new WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION(
memory);
- int returnedStructCount = bufferSize.getValue().intValue()
- / sizePerStruct;
return (WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]) firstInformation
.toArray(new WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0]);
}
+ /**
+ * Convenience method to get the processor information. Takes care of
+ * auto-growing the array and populating variable-length arrays in
+ * structures.
+ *
+ * @param relationshipType
+ * The type of relationship to retrieve. This parameter can be
+ * one of the following values:
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationCache},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationGroup},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationNumaNode},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage},
+ * or {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationAll}
+ * @return the array of processor information.
+ */
+ public static final SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX[] getLogicalProcessorInformationEx(
+ int relationshipType) {
+ WinDef.DWORDByReference bufferSize = new WinDef.DWORDByReference(new WinDef.DWORD(1));
+ Memory memory;
+ while (true) {
+ memory = new Memory(bufferSize.getValue().intValue());
+ if (!Kernel32.INSTANCE.GetLogicalProcessorInformationEx(relationshipType, memory, bufferSize)) {
+ int err = Kernel32.INSTANCE.GetLastError();
+ if (err != WinError.ERROR_INSUFFICIENT_BUFFER)
+ throw new Win32Exception(err);
+ } else {
+ break;
+ }
+ }
+ // Array elements have variable size; iterate to populate array
+ List
+ * The native structure contains a union, which is mapped to JNA as
+ * subclasses.
+ */
+ @FieldOrder({ "relationship", "size" })
+ public abstract class SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX extends Structure {
+
+ /**
+ * The type of relationship between the logical processors. This
+ * parameter can be one of the following values:
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationCache},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationGroup},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationNumaNode},
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore}, or
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage}.
+ *
+ * This field identifies which subclass will be instantiated by the
+ * {@link #fromPointer(Pointer)} method.
+ */
+ public int /* LOGICAL_PROCESSOR_RELATIONSHIP */ relationship;
+
+ /**
+ * The size of the structure, in bytes.
+ */
+ public int size;
+
+ public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX() {
+ super();
+ }
+
+ /**
+ * This constructor should only be called by a subclass to ensure memory
+ * is properly allocated to the subclass fields.
+ *
+ * @param memory
+ * A pointer to the allocated native memory.
+ */
+ protected SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Pointer memory) {
+ super(memory);
+ }
+
+ /**
+ * Create a new instance of the appropriate subclass of
+ * {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} from the provided
+ * {@link Pointer} to native memory. Use this method rather than
+ * {@link #SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Pointer)} to properly
+ * cast the Pointer to the appropriate subclass and populate variable
+ * length arrays.
+ *
+ * @param memory
+ * A pointer to allocated memory to be cast to this class.
+ * @return An instance of the appropriate subclass depending on the
+ * value of the {@link #relationship} field. If the
+ * {@link #relationship} member is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore}
+ * or
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage},
+ * the return type will be {@link PROCESSOR_RELATIONSHIP}. If
+ * the {@link #relationship} member is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationNumaNode}, the
+ * return type will be {@link NUMA_NODE_RELATIONSHIP}. If the
+ * {@link #relationship} member is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationCache}, the
+ * return type will be {@link CACHE_RELATIONSHIP}. If the
+ * {@link #relationship} member is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationGroup}, the
+ * return type will be {@link GROUP_RELATIONSHIP}.
+ */
+ public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX fromPointer(Pointer memory) {
+ int relationship = memory.getInt(0);
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX result;
+ switch (relationship) {
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore:
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage:
+ result = new PROCESSOR_RELATIONSHIP(memory);
+ break;
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode:
+ result = new NUMA_NODE_RELATIONSHIP(memory);
+ break;
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache:
+ result = new CACHE_RELATIONSHIP(memory);
+ break;
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup:
+ result = new GROUP_RELATIONSHIP(memory);
+ break;
+ default:
+ throw new IllegalStateException("Unmapped relationship: " + relationship);
+ }
+ result.read();
+ return result;
+ }
+ }
+
+ /**
+ * Describes the logical processors associated with either a processor core
+ * or a processor package.
+ */
+ @FieldOrder({ "flags", "efficiencyClass", "reserved", "groupCount", "groupMask" })
+ public static class PROCESSOR_RELATIONSHIP extends SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+
+ /**
+ * If the {@link #relationship} member of the
+ * {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} structure is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore}, this
+ * member is {@link #LTP_PC_SMT} if the core has more than one logical
+ * processor, or 0 if the core has one logical processor.
+ *
+ * If the {@link #relationship} member of the
+ * {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} structure is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage}, this
+ * member is always 0.
+ */
+ public byte flags;
+
+ /**
+ * If the {@link #relationship} member of the
+ * {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} structure is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorCore},
+ * EfficiencyClass specifies the intrinsic tradeoff between performance
+ * and power for the applicable core. A core with a higher value for the
+ * efficiency class has intrinsically greater performance and less
+ * efficiency than a core with a lower value for the efficiency class.
+ * EfficiencyClass is only nonzero on systems with a heterogeneous set
+ * of cores.
+ *
+ * If the {@link #relationship} member of the
+ * {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} structure is
+ * {@link LOGICAL_PROCESSOR_RELATIONSHIP#RelationProcessorPackage},
+ * EfficiencyClass is always 0.
+ *
+ * The minimum operating system version that supports this member is
+ * Windows 10.
+ */
+ public byte efficiencyClass;
+
+ /**
+ * This member is reserved.
+ */
+ public byte[] reserved = new byte[20];
+
+ /**
+ * This member specifies the number of entries in the GroupMask array.
+ *
+ * If the PROCESSOR_RELATIONSHIP structure represents a processor core,
+ * the GroupCount member is always 1.
+ *
+ * If the {@link PROCESSOR_RELATIONSHIP} structure represents a
+ * processor package, the {@link #groupCount} member is 1 only if all
+ * processors are in the same processor group. If the package contains
+ * more than one NUMA node, the system might assign different NUMA nodes
+ * to different processor groups. In this case, the {@link #groupCount}
+ * member is the number of groups to which NUMA nodes in the package are
+ * assigned.
+ */
+ public short groupCount;
+
+ /**
+ * An array of {@link GROUP_AFFINITY} structures. The
+ * {@link #groupCount} member specifies the number of structures in the
+ * array. Each structure in the array specifies a group number and
+ * processor affinity within the group.
+ */
+ public GROUP_AFFINITY[] groupMask = new GROUP_AFFINITY[1];
+
+ public PROCESSOR_RELATIONSHIP() {
+ }
+
+ public PROCESSOR_RELATIONSHIP(Pointer memory) {
+ super(memory);
+ }
+
+ @Override
+ public void read() {
+ readField("groupCount");
+ groupMask = new GROUP_AFFINITY[groupCount];
+ super.read();
+ }
+ }
+
+ /**
+ * Represents information about a NUMA node in a processor group.
+ */
+ @FieldOrder({ "nodeNumber", "reserved", "groupMask" })
+ public static class NUMA_NODE_RELATIONSHIP extends SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+
+ /**
+ * Identifies the NUMA node. Valid values are {@code 0} to the highest
+ * NUMA node number inclusive. A non-NUMA multiprocessor system will
+ * report that all processors belong to one NUMA node.
+ */
+ public int nodeNumber;
+
+ /**
+ * This member is reserved.
+ */
+ public byte[] reserved = new byte[20];
+
+ /**
+ * A {@link GROUP_AFFINITY} structure that specifies a group number and
+ * processor affinity within the group.
+ */
+ public GROUP_AFFINITY groupMask;
+
+ public NUMA_NODE_RELATIONSHIP() {
+ }
+
+ public NUMA_NODE_RELATIONSHIP(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Describes cache attributes.
+ */
+ @FieldOrder({ "level", "associativity", "lineSize", "cacheSize", "type", "reserved", "groupMask" })
+ public static class CACHE_RELATIONSHIP extends SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+
+ /**
+ * The cache level. This member can be 1 (L1), 2 (L2), 3 (L3), or 4
+ * (L4).
+ */
+ public byte level;
+
+ /**
+ * The cache associativity. If this member is
+ * {@link #CACHE_FULLY_ASSOCIATIVE}, the cache is fully associative.
+ */
+ public byte associativity;
+
+ /**
+ * The cache line size, in bytes.
+ */
+ public short lineSize;
+
+ /**
+ * The cache size, in bytes.
+ */
+ public int cacheSize;
+
+ /**
+ * The cache type. This member is a {@link PROCESSOR_CACHE_TYPE} value.
+ */
+ public int /* PROCESSOR_CACHE_TYPE */ type;
+
+ /**
+ * This member is reserved.
+ */
+ public byte[] reserved = new byte[20];
+
+ /**
+ * A {@link GROUP_AFFINITY} structure that specifies a group number and
+ * processor affinity within the group.
+ */
+ public GROUP_AFFINITY groupMask;
+
+ public CACHE_RELATIONSHIP() {
+ }
+
+ public CACHE_RELATIONSHIP(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Represents information about processor groups.
+ */
+ @FieldOrder({ "maximumGroupCount", "activeGroupCount", "reserved", "groupInfo" })
+ public static class GROUP_RELATIONSHIP extends SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+
+ /**
+ * The maximum number of processor groups on the system.
+ */
+ public short maximumGroupCount;
+
+ /**
+ * The number of active groups on the system. This member indicates the
+ * number of {@link PROCESSOR_GROUP_INFO} structures in the GroupInfo
+ * array.
+ */
+ public short activeGroupCount;
+
+ /**
+ * This member is reserved.
+ */
+ public byte[] reserved = new byte[20];
+
+ /**
+ * An array of {@link PROCESSOR_GROUP_INFO} structures. The
+ * {@link #activeGroupCount} member specifies the number of structures
+ * in the array. Each structure in the array specifies the number and
+ * affinity of processors in an active group on the system.
+ */
+ public PROCESSOR_GROUP_INFO[] groupInfo = new PROCESSOR_GROUP_INFO[1];
+
+ public GROUP_RELATIONSHIP() {
+ }
+
+ public GROUP_RELATIONSHIP(Pointer memory) {
+ super(memory);
+ }
+
+ @Override
+ public void read() {
+ readField("activeGroupCount");
+ groupInfo = new PROCESSOR_GROUP_INFO[activeGroupCount];
+ super.read();
+ }
+ }
+
+ /**
+ * Represents a processor group-specific affinity, such as the affinity of a
+ * thread.
+ */
+ @FieldOrder({ "mask", "group", "reserved" })
+ public static class GROUP_AFFINITY extends Structure {
+
+ /**
+ * A bitmap that specifies the affinity for zero or more processors
+ * within the specified group.
+ */
+ public ULONG_PTR /* KAFFINITY */ mask;
+
+ /**
+ * The processor group number.
+ */
+ public short group;
+
+ /**
+ * This member is reserved.
+ */
+ public short[] reserved = new short[3];
+
+ public GROUP_AFFINITY(Pointer memory) {
+ super(memory);
+ }
+
+ public GROUP_AFFINITY() {
+ super();
+ }
+ }
+
+ /**
+ * Represents the number and affinity of processors in a processor group.
+ */
+ @FieldOrder({ "maximumProcessorCount", "activeProcessorCount", "reserved", "activeProcessorMask" })
+ public static class PROCESSOR_GROUP_INFO extends Structure {
+
+ /**
+ * The maximum number of processors in the group.
+ */
+ public byte maximumProcessorCount;
+
+ /**
+ * The number of active processors in the group.
+ */
+ public byte activeProcessorCount;
+
+ /**
+ * This member is reserved.
+ */
+ public byte[] reserved = new byte[38];
+
+ /**
+ * A bitmap that specifies the affinity for zero or more active
+ * processors within the group.
+ */
+ public ULONG_PTR /* KAFFINITY */ activeProcessorMask;
+
+ public PROCESSOR_GROUP_INFO(Pointer memory) {
+ super(memory);
+ }
+
+ public PROCESSOR_GROUP_INFO() {
+ super();
+ }
+ }
+
/**
* Represents the relationship between the processor set identified in the corresponding
* {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION} or SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
structure.
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java
index 45c33f060c..4c8a84ccb3 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java
@@ -19,15 +19,23 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W;
+import com.sun.jna.platform.win32.WinNT.CACHE_RELATIONSHIP;
+import com.sun.jna.platform.win32.WinNT.GROUP_RELATIONSHIP;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;
+import com.sun.jna.platform.win32.WinNT.LOGICAL_PROCESSOR_RELATIONSHIP;
+import com.sun.jna.platform.win32.WinNT.NUMA_NODE_RELATIONSHIP;
+import com.sun.jna.platform.win32.WinNT.PROCESSOR_CACHE_TYPE;
+import com.sun.jna.platform.win32.WinNT.PROCESSOR_RELATIONSHIP;
+import com.sun.jna.platform.win32.WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
import junit.framework.TestCase;
@@ -347,4 +355,109 @@ public void testExpandEnvironmentStrings() {
Kernel32.INSTANCE.SetEnvironmentVariable("DemoVariable", "DemoValue");
assertEquals("DemoValue", Kernel32Util.expandEnvironmentStrings("%DemoVariable%"));
}
+
+ public void testGetLogicalProcessorInformationEx() {
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX[] procInfo = Kernel32Util
+ .getLogicalProcessorInformationEx(WinNT.LOGICAL_PROCESSOR_RELATIONSHIP.RelationAll);
+ List