diff --git a/stl/msbuild/stl_base/msvcp.settings.targets b/stl/msbuild/stl_base/msvcp.settings.targets
index ea0f763c3da..825cf4929eb 100644
--- a/stl/msbuild/stl_base/msvcp.settings.targets
+++ b/stl/msbuild/stl_base/msvcp.settings.targets
@@ -71,6 +71,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
diff --git a/stl/src/cthread.cpp b/stl/src/cthread.cpp
index 731f9296cb4..f4e53aaaf99 100644
--- a/stl/src/cthread.cpp
+++ b/stl/src/cthread.cpp
@@ -1,10 +1,12 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#include
#include
#include
#include
#include
+#include
#include
#include
@@ -103,9 +105,55 @@ _CRTIMP2_PURE _Thrd_id_t __cdecl _Thrd_id() noexcept { // return unique id for c
}
_CRTIMP2_PURE unsigned int __cdecl _Thrd_hardware_concurrency() noexcept { // return number of processors
- SYSTEM_INFO info;
- GetNativeSystemInfo(&info);
- return info.dwNumberOfProcessors;
+ // Most devices have only one processor group and thus have the same buffer_size.
+#ifdef _WIN64
+ constexpr int stack_buffer_size = 48; // 16 bytes per group
+#else // ^^^ 64-bit / 32-bit vvv
+ constexpr int stack_buffer_size = 44; // 12 bytes per group
+#endif // ^^^ 32-bit ^^^
+
+ alignas(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) unsigned char stack_buffer[stack_buffer_size];
+ unsigned char* buffer_ptr = stack_buffer;
+ DWORD buffer_size = stack_buffer_size;
+ _STD unique_ptr new_buffer;
+
+ // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
+ // The buffer "receives a sequence of variable-sized SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structures".
+ for (;;) {
+ if (GetLogicalProcessorInformationEx(RelationProcessorPackage,
+ reinterpret_cast(buffer_ptr), &buffer_size)) {
+ unsigned int logical_processors = 0;
+
+ while (buffer_size > 0) {
+ // Each structure in the buffer describes a processor package (aka socket)...
+ const auto structure_ptr = reinterpret_cast(buffer_ptr);
+ const auto structure_size = structure_ptr->Size;
+
+ // ... which contains one or more processor groups.
+ for (WORD i = 0; i != structure_ptr->Processor.GroupCount; ++i) {
+ logical_processors += _STD popcount(structure_ptr->Processor.GroupMask[i].Mask);
+ }
+
+ // Step forward to the next structure in the buffer.
+ buffer_ptr += structure_size;
+ buffer_size -= structure_size;
+ }
+
+ return logical_processors;
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return 0; // API failure
+ }
+
+ new_buffer.reset(::new (_STD nothrow) unsigned char[buffer_size]);
+
+ if (!new_buffer) {
+ return 0; // allocation failure
+ }
+
+ buffer_ptr = new_buffer.get();
+ }
}
// TRANSITION, ABI: _Thrd_create() is preserved for binary compatibility