diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 85c523881ef..f127077a899 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -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(); 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;