ntdll: Implement NtQuerySystemInformationEx(SystemCpuSetInformation).

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2021-03-30 13:37:39 +03:00 committed by Alexandre Julliard
parent 7ff591d7de
commit 084519a82b
4 changed files with 246 additions and 0 deletions

View File

@ -1099,6 +1099,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 = malloc(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);
}
free(info);
}
static void test_query_firmware(void)
{
static const ULONG min_sfti_len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
@ -3059,6 +3142,7 @@ START_TEST(info)
test_query_regquota();
test_query_logicalproc();
test_query_logicalprocex();
test_query_cpusetinfo();
test_query_firmware();
test_query_data_alignment();

View File

@ -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;

View File

@ -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;

View File

@ -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;