[PATCH v3 1/2] ntdll: Implement NtQuerySystemInformationEx(SystemCpuSetInformation).

Paul Gofman pgofman at codeweavers.com
Tue Mar 30 05:37:39 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v3:
    - also remove is_win64 from tests.

 dlls/ntdll/tests/info.c  |  85 +++++++++++++++++++++++++++
 dlls/ntdll/unix/system.c | 120 +++++++++++++++++++++++++++++++++++++++
 include/winnt.h          |  41 +++++++++++++
 include/winternl.h       |   1 +
 4 files changed, 247 insertions(+)

diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 85c523881ef..2c0b95d34c6 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -21,6 +21,7 @@
 #include "ntdll_test.h"
 #include <winnls.h>
 #include <stdio.h>
+#include "wine/heap.h"
 
 static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
 static NTSTATUS (WINAPI * pNtSetSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG);
@@ -1099,6 +1100,89 @@ static void test_query_logicalprocex(void)
     HeapFree(GetProcessHeap(), 0, infoex_group);
 }
 
+static void test_query_cpusetinfo(void)
+{
+    SYSTEM_CPU_SET_INFORMATION *info;
+    unsigned int i, cpu_count;
+    ULONG len, expected_len;
+    NTSTATUS status;
+    SYSTEM_INFO si;
+    HANDLE process;
+
+    if (!pNtQuerySystemInformationEx)
+        return;
+
+    GetSystemInfo(&si);
+    cpu_count = si.dwNumberOfProcessors;
+    expected_len = cpu_count * sizeof(*info);
+
+    process = GetCurrentProcess();
+
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), NULL, 0, &len);
+    if (status == STATUS_INVALID_INFO_CLASS)
+    {
+        win_skip("SystemCpuSetInformation is not supported\n");
+        return;
+    }
+
+    ok(status == STATUS_BUFFER_TOO_SMALL, "Got unexpected status %#x.\n", status);
+    ok(len == expected_len, "Got unexpected length %u.\n", len);
+
+    len = 0xdeadbeef;
+    status = pNtQuerySystemInformation(SystemCpuSetInformation, NULL, 0, &len);
+    ok(status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_INFO_CLASS,
+            "Got unexpected status %#x.\n", status);
+    ok(len == 0xdeadbeef, "Got unexpected len %u.\n", len);
+
+    len = 0xdeadbeef;
+    process = (HANDLE)0xdeadbeef;
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), NULL, 0, &len);
+    ok(status == STATUS_INVALID_HANDLE, "Got unexpected status %#x.\n", status);
+    ok(len == 0xdeadbeef, "Got unexpected length %u.\n", len);
+
+    len = 0xdeadbeef;
+    process = NULL;
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, 4 * sizeof(process), NULL, 0, &len);
+    ok((status == STATUS_INVALID_PARAMETER && len == 0xdeadbeef)
+            || (status == STATUS_BUFFER_TOO_SMALL && len == expected_len),
+            "Got unexpected status %#x, length %u.\n", status, len);
+
+    len = 0xdeadbeef;
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, NULL, sizeof(process), NULL, 0, &len);
+    ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#x.\n", status);
+    ok(len == 0xdeadbeef, "Got unexpected length %u.\n", len);
+
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), NULL, 0, &len);
+    ok(status == STATUS_BUFFER_TOO_SMALL, "Got unexpected status %#x.\n", status);
+    ok(len == expected_len, "Got unexpected length %u.\n", len);
+
+    len = 0xdeadbeef;
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), NULL,
+            expected_len, &len);
+    ok(status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#x.\n", status);
+    ok(len == 0xdeadbeef, "Got unexpected length %u.\n", len);
+
+    info = heap_alloc(expected_len);
+    len = 0;
+    status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), info, expected_len, &len);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    ok(len == expected_len, "Got unexpected length %u.\n", len);
+
+    for (i = 0; i < cpu_count; ++i)
+    {
+        SYSTEM_CPU_SET_INFORMATION *d = &info[i];
+
+        ok(d->Size == sizeof(*d), "Got unexpected size %u, i %u.\n", d->Size, i);
+        ok(d->Type == CpuSetInformation, "Got unexpected type %u, i %u.\n", d->Type, i);
+        ok(d->CpuSet.Id == 0x100 + i, "Got unexpected Id %#x, i %u.\n", d->CpuSet.Id, i);
+        ok(!d->CpuSet.Group, "Got unexpected Group %u, i %u.\n", d->CpuSet.Group, i);
+        ok(d->CpuSet.LogicalProcessorIndex == i, "Got unexpected LogicalProcessorIndex %u, i %u.\n",
+                d->CpuSet.LogicalProcessorIndex, i);
+        ok(!d->CpuSet.AllFlags, "Got unexpected AllFlags %#x, i %u.\n", d->CpuSet.AllFlags, i);
+    }
+    heap_free(info);
+}
+
 static void test_query_firmware(void)
 {
     static const ULONG min_sfti_len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
@@ -3059,6 +3143,7 @@ START_TEST(info)
     test_query_regquota();
     test_query_logicalproc();
     test_query_logicalprocex();
+    test_query_cpusetinfo();
     test_query_firmware();
     test_query_data_alignment();
 
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index 6fa71ddfb91..a9cd686ed62 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -1166,6 +1166,98 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION *
 }
 #endif
 
+static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info)
+{
+    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *proc_info;
+    BYTE core_index, cache_index, max_cache_level;
+    unsigned int i, j, count;
+    BYTE *proc_info_buffer;
+    DWORD cpu_info_size;
+    ULONG64 cpu_mask;
+    NTSTATUS status;
+
+    count = NtCurrentTeb()->Peb->NumberOfProcessors;
+
+    cpu_info_size = 3 * sizeof(*proc_info);
+    if (!(proc_info_buffer = malloc(cpu_info_size)))
+        return STATUS_NO_MEMORY;
+
+    if ((status = create_logical_proc_info(NULL, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **)&proc_info_buffer,
+            &cpu_info_size, RelationAll)))
+    {
+        free(proc_info_buffer);
+        return status;
+    }
+
+    max_cache_level = 0;
+    proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)proc_info_buffer;
+    for (i = 0; (BYTE *)proc_info != proc_info_buffer + cpu_info_size; ++i)
+    {
+        if (proc_info->Relationship == RelationCache)
+        {
+            if (max_cache_level < proc_info->u.Cache.Level)
+                max_cache_level = proc_info->u.Cache.Level;
+        }
+        proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
+    }
+
+    memset(info, 0, count * sizeof(*info));
+
+    core_index = 0;
+    cache_index = 0;
+    proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)proc_info_buffer;
+    for (i = 0; i < count; ++i)
+    {
+        info[i].Size = sizeof(*info);
+        info[i].Type = CpuSetInformation;
+        info[i].u.CpuSet.Id = 0x100 + i;
+        info[i].u.CpuSet.LogicalProcessorIndex = i;
+    }
+
+    for (i = 0; (BYTE *)proc_info != (BYTE *)proc_info_buffer + cpu_info_size; ++i)
+    {
+        if (proc_info->Relationship == RelationProcessorCore)
+        {
+            if (proc_info->u.Processor.GroupCount != 1)
+            {
+                FIXME("Unsupported group count %u.\n", proc_info->u.Processor.GroupCount);
+                continue;
+            }
+            cpu_mask = proc_info->u.Processor.GroupMask[0].Mask;
+            for (j = 0; j < count; ++j)
+                if (((ULONG64)1 << j) & cpu_mask)
+                {
+                    info[j].u.CpuSet.CoreIndex = core_index;
+                    info[j].u.CpuSet.EfficiencyClass = proc_info->u.Processor.EfficiencyClass;
+                }
+            ++core_index;
+        }
+        else if (proc_info->Relationship == RelationCache)
+        {
+            if (proc_info->u.Cache.Level == max_cache_level)
+            {
+                cpu_mask = proc_info->u.Cache.GroupMask.Mask;
+                for (j = 0; j < count; ++j)
+                    if (((ULONG64)1 << j) & cpu_mask)
+                        info[j].u.CpuSet.LastLevelCacheIndex = cache_index;
+            }
+            ++cache_index;
+        }
+        else if (proc_info->Relationship == RelationNumaNode)
+        {
+            cpu_mask = proc_info->u.NumaNode.GroupMask.Mask;
+            for (j = 0; j < count; ++j)
+                if (((ULONG64)1 << j) & cpu_mask)
+                    info[j].u.CpuSet.NumaNodeIndex = proc_info->u.NumaNode.NodeNumber;
+        }
+        proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
+    }
+
+    free(proc_info_buffer);
+
+    return STATUS_SUCCESS;
+}
+
 #ifdef linux
 
 static void copy_smbios_string( char **buffer, char *s, size_t len )
@@ -2651,6 +2743,9 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
         break;
     }
 
+    case SystemCpuSetInformation:
+        return NtQuerySystemInformationEx(class, NULL, 0, info, size, ret_size);
+
     case SystemRecommendedSharedDataAlignment:
     {
         len = sizeof(DWORD);
@@ -2773,6 +2868,31 @@ NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
         break;
     }
 
+    case SystemCpuSetInformation:
+    {
+        unsigned int cpu_count = NtCurrentTeb()->Peb->NumberOfProcessors;
+        PROCESS_BASIC_INFORMATION pbi;
+        HANDLE process;
+
+        if (!query || query_len < sizeof(HANDLE))
+            return STATUS_INVALID_PARAMETER;
+
+        process = *(HANDLE *)query;
+        if (process && (ret = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL)))
+            return ret;
+
+        if (size < (len = cpu_count * sizeof(SYSTEM_CPU_SET_INFORMATION)))
+        {
+            ret = STATUS_BUFFER_TOO_SMALL;
+            break;
+        }
+        if (!info)
+            return STATUS_ACCESS_VIOLATION;
+
+        if ((ret = create_cpuset_info(info)))
+            return ret;
+        break;
+    }
     default:
         FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
         break;
diff --git a/include/winnt.h b/include/winnt.h
index 0a6027118fe..840966f657b 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -6726,6 +6726,47 @@ typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
     } DUMMYUNIONNAME;
 } SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
 
+typedef enum _CPU_SET_INFORMATION_TYPE
+{
+    CpuSetInformation,
+} CPU_SET_INFORMATION_TYPE, *PCPU_SET_INFORMATION_TYPE;
+
+typedef struct _SYSTEM_CPU_SET_INFORMATION
+{
+    DWORD Size;
+    CPU_SET_INFORMATION_TYPE Type;
+    union
+    {
+        struct
+        {
+            DWORD Id;
+            WORD Group;
+            BYTE LogicalProcessorIndex;
+            BYTE CoreIndex;
+            BYTE LastLevelCacheIndex;
+            BYTE NumaNodeIndex;
+            BYTE EfficiencyClass;
+            union
+            {
+                BYTE AllFlags;
+                struct
+                {
+                    BYTE Parked : 1;
+                    BYTE Allocated : 1;
+                    BYTE AllocatedToTargetProcess : 1;
+                    BYTE RealTime : 1;
+                    BYTE ReservedFlags : 4;
+                } DUMMYSTRUCTNAME;
+            } DUMMYUNIONNAME2;
+            union {
+            DWORD Reserved;
+            BYTE  SchedulingClass;
+            };
+            DWORD64 AllocationTag;
+        } CpuSet;
+    } DUMMYUNIONNAME;
+} SYSTEM_CPU_SET_INFORMATION, *PSYSTEM_CPU_SET_INFORMATION;
+
 /* Threadpool things */
 typedef DWORD TP_VERSION,*PTP_VERSION;
 
diff --git a/include/winternl.h b/include/winternl.h
index fcdedaec8aa..c8fb7031d91 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1551,6 +1551,7 @@ typedef enum _SYSTEM_INFORMATION_CLASS {
     SystemFileCacheInformationEx = 81,
     SystemDynamicTimeZoneInformation = 102,
     SystemLogicalProcessorInformationEx = 107,
+    SystemCpuSetInformation = 175,
     SystemHypervisorSharedPageInformation = 197,
     SystemInformationClassMax
 } SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;
-- 
2.30.2




More information about the wine-devel mailing list