[libcxx-commits] [libcxx] [libc++] Make __thread_hardware_concurrency() an alias to an existing symbol (PR #234575)
Michael G. Kazakov via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Oct 24 02:54:56 PDT 2026
https://github.com/mikekazakov updated https://github.com/llvm/llvm-project/pull/234575
>From 3a4c4d806427dc2b789254f5805d5eaf76664d1e Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 22 Oct 2026 11:49:40 +0100
Subject: [PATCH 1/5] Make __thread_hardware_concurrency() an alias to an
existing symbol
---
libcxx/include/__configuration/availability.h | 6 ---
.../include/__thread/hardware_concurrency.h | 28 ++++++++++-
libcxx/include/__thread/thread.h | 7 ---
libcxx/lib/abi/CHANGELOG.TXT | 6 ---
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 -
...xxabi.v1.stable.noexceptions.nonew.abilist | 1 -
libcxx/src/thread.cpp | 49 +++++++++----------
.../tmp.hardware_concurrency_func.pass.cpp | 27 ++++++++++
15 files changed, 76 insertions(+), 56 deletions(-)
create mode 100644 libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 805a9edab14bb..75d911438e4af 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -260,12 +260,6 @@
#endif
-// This controls the availability of the free function std::__thread_hardware_concurrency().
-// It has the same semantics as std::[j]thread::hardware_concurrency(), but allows to query this information
-// without depending on std::thread itself.
-#define _LIBCPP_AVAILABILITY_HAS_HARDWARE_CONCURRENCY_FREE_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_24
-#define _LIBCPP_AVAILABILITY_HARDWARE_CONCURRENCY_FREE_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE
-
// This controls the availability of the C++26 debugging functions.
// The platform specific implementation is built in the library.
#define _LIBCPP_AVAILABILITY_HAS_DEBUGGING _LIBCPP_INTRODUCED_IN_LLVM_24
diff --git a/libcxx/include/__thread/hardware_concurrency.h b/libcxx/include/__thread/hardware_concurrency.h
index c5ee41686a939..043e3883bec6f 100644
--- a/libcxx/include/__thread/hardware_concurrency.h
+++ b/libcxx/include/__thread/hardware_concurrency.h
@@ -24,8 +24,32 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_HAS_THREADS
-[[__nodiscard__]] _LIBCPP_AVAILABILITY_HARDWARE_CONCURRENCY_FREE_FUNCTION
- _LIBCPP_EXPORTED_FROM_ABI unsigned __thread_hardware_concurrency() _NOEXCEPT;
+// __thread_hardware_concurrency() has the same semantics as std::[j]thread::hardware_concurrency(), but allows querying
+// this information without depending on std::thread itself. Rather than adding a new symbol to the built library, it is
+// declared as an alias of std::thread::hardware_concurrency(), which has always been part of the ABI.
+
+# define _LIBCPP_THREAD_ABI_NAMESPACE_STR _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE)
+
+# ifdef _LIBCPP_ABI_MICROSOFT
+# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
+ "?hardware_concurrency at thread@" _LIBCPP_THREAD_ABI_NAMESPACE_STR "@std@@SAIXZ"
+# else
+// The Itanium mangling of a namespace name is prefixed with its length, which can't be computed by the preprocessor.
+# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___1 3
+# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___2 3
+# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___ndk1 6
+# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH _LIBCPP_CONCAT(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH_, _LIBCPP_ABI_NAMESPACE)
+# if _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH == 0
+# error "Unknown length of _LIBCPP_ABI_NAMESPACE, add it to <__thread/hardware_concurrency.h>"
+# endif
+# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
+ _LIBCPP_TOSTRING(__USER_LABEL_PREFIX__) \
+ "_ZNSt" _LIBCPP_TOSTRING(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH) _LIBCPP_THREAD_ABI_NAMESPACE_STR \
+ "6thread20hardware_concurrencyEv"
+# endif
+
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned __thread_hardware_concurrency() _NOEXCEPT
+ __asm__(_LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL);
#endif // _LIBCPP_HAS_THREADS
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index 750a2d2a59ce7..42427cb63269f 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -263,14 +263,7 @@ class _LIBCPP_EXPORTED_FROM_ABI thread {
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; }
-# if defined(_LIBCPP_BUILDING_LIBRARY) || !_LIBCPP_AVAILABILITY_HAS_HARDWARE_CONCURRENCY_FREE_FUNCTION
[[__nodiscard__]] static unsigned hardware_concurrency() _NOEXCEPT;
-# else
- // Always inline to avoid an ODR violation with the symbol defined in the built library
- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static unsigned hardware_concurrency() _NOEXCEPT {
- return std::__thread_hardware_concurrency();
- }
-# endif
};
inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); }
diff --git a/libcxx/lib/abi/CHANGELOG.TXT b/libcxx/lib/abi/CHANGELOG.TXT
index 05f4a14540270..85d2e596ed51f 100644
--- a/libcxx/lib/abi/CHANGELOG.TXT
+++ b/libcxx/lib/abi/CHANGELOG.TXT
@@ -16,12 +16,6 @@ New entries should be added directly below the "Version" header.
Version 24.0
------------
-* [libc++] Add <__thread/hardware_concurrency.h> __thread_hardware_concurrency()
-
- All platforms
- -------------
- Symbol added: _ZNSt3__129__thread_hardware_concurrencyEv
-
* [libc++] Remove locale::id::__next_id from the ABI
`__next_id` is only ever used inside the dylib, so we can avoid making it public.
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 186159115eace..74e0af974e453 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1586,7 +1586,6 @@
{'is_defined': True, 'name': '__ZNSt3__126__atomic_wait_global_tableEPKvx', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index f423cab70fff6..1b0cd758bfcf3 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1223,7 +1223,6 @@
{'is_defined': True, 'name': '_ZNSt6__ndk126__atomic_wait_global_tableEPKvi', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index d121aba28c662..c61db56dc2b90 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -573,7 +573,6 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__126__atomic_wait_global_tableEPKvi', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__129__thread_hardware_concurrencyEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_all_global_tableEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_one_global_tableEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 69b0833420bc8..7663aa877a096 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -573,7 +573,6 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__126__atomic_wait_global_tableEPKvl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__129__thread_hardware_concurrencyEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_all_global_tableEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_one_global_tableEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index e290f961ba632..00b5949f843ac 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1579,7 +1579,6 @@
{'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointEPKcS1_RdNS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointEPKcS1_RfNS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index cc027ffd7eb0a..536614e0ccfa6 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1223,7 +1223,6 @@
{'is_defined': True, 'name': '_ZNSt6__ndk126__atomic_wait_global_tableEPKvi', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index eb1638841be7a..d655541acdc8d 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1236,7 +1236,6 @@
{'is_defined': True, 'name': '_ZNSt3__126__atomic_wait_global_tableEPKvl', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 880cb2504c084..69c32bd5be877 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1234,7 +1234,6 @@
{'is_defined': True, 'name': '_ZNSt3__126__atomic_wait_global_tableEPKvi', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index b5187b4ec82d4..b6850b2ec8093 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1205,7 +1205,6 @@
{'is_defined': True, 'name': '_ZNSt3__126__atomic_wait_global_tableEPKvi', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__129__thread_hardware_concurrencyEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_all_global_tableEPKv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__132__atomic_notify_one_global_tableEPKv', 'type': 'FUNC'}
diff --git a/libcxx/src/thread.cpp b/libcxx/src/thread.cpp
index 17b36c15f5581..7b0890858e9d6 100644
--- a/libcxx/src/thread.cpp
+++ b/libcxx/src/thread.cpp
@@ -64,8 +64,29 @@ void thread::detach() {
std::__throw_system_error(ec, "thread::detach failed");
}
-// Defined here only for backwards compatibility.
-unsigned thread::hardware_concurrency() noexcept { return std::__thread_hardware_concurrency(); }
+unsigned thread::hardware_concurrency() noexcept {
+#if defined(_SC_NPROCESSORS_ONLN)
+ long result = sysconf(_SC_NPROCESSORS_ONLN);
+ // sysconf returns -1 if the name is invalid, the option does not exist or
+ // does not have a definite limit.
+ // if sysconf returns some other negative number, we have no idea
+ // what is going on. Default to something safe.
+ if (result < 0)
+ return 0;
+ return static_cast<unsigned>(result);
+#elif defined(_WIN32)
+ return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS));
+#else // defined(CTL_HW) && defined(HW_NCPU)
+ // TODO: grovel through /proc or check cpuid on x86 and similar
+ // instructions on other architectures.
+# if defined(_LIBCPP_WARNING)
+ _LIBCPP_WARNING("hardware_concurrency not yet implemented")
+# else
+# warning hardware_concurrency not yet implemented
+# endif
+ return 0; // Means not computable [thread.thread.static]
+#endif // defined(CTL_HW) && defined(HW_NCPU)
+}
namespace this_thread {
@@ -150,29 +171,5 @@ void __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m
void __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) { __p_->__make_ready_at_thread_exit(__s); }
-unsigned __thread_hardware_concurrency() noexcept {
-#if defined(_SC_NPROCESSORS_ONLN)
- long result = sysconf(_SC_NPROCESSORS_ONLN);
- // sysconf returns -1 if the name is invalid, the option does not exist or
- // does not have a definite limit.
- // if sysconf returns some other negative number, we have no idea
- // what is going on. Default to something safe.
- if (result < 0)
- return 0;
- return static_cast<unsigned>(result);
-#elif defined(_WIN32)
- return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS));
-#else // defined(CTL_HW) && defined(HW_NCPU)
- // TODO: grovel through /proc or check cpuid on x86 and similar
- // instructions on other architectures.
-# if defined(_LIBCPP_WARNING)
- _LIBCPP_WARNING("hardware_concurrency not yet implemented")
-# else
-# warning hardware_concurrency not yet implemented
-# endif
- return 0; // Means not computable [thread.thread.static]
-#endif // defined(CTL_HW) && defined(HW_NCPU)
-}
-
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
new file mode 100644
index 0000000000000..e380b4470ecc3
--- /dev/null
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: no-threads
+
+// <thread>
+
+// class thread
+
+// unsigned hardware_concurrency();
+
+#include <thread>
+#include <__thread/hardware_concurrency.h>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ assert(std::thread::hardware_concurrency() == std::__thread_hardware_concurrency());
+
+ return 0;
+}
>From 900da96428da3dabd92878de35dae484740d6adc Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 22 Oct 2026 11:54:35 +0100
Subject: [PATCH 2/5] clang-format
---
libcxx/include/__thread/hardware_concurrency.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__thread/hardware_concurrency.h b/libcxx/include/__thread/hardware_concurrency.h
index 043e3883bec6f..c378cba66059a 100644
--- a/libcxx/include/__thread/hardware_concurrency.h
+++ b/libcxx/include/__thread/hardware_concurrency.h
@@ -38,14 +38,15 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___1 3
# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___2 3
# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___ndk1 6
-# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH _LIBCPP_CONCAT(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH_, _LIBCPP_ABI_NAMESPACE)
+# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH \
+ _LIBCPP_CONCAT(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH_, _LIBCPP_ABI_NAMESPACE)
# if _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH == 0
# error "Unknown length of _LIBCPP_ABI_NAMESPACE, add it to <__thread/hardware_concurrency.h>"
# endif
# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
_LIBCPP_TOSTRING(__USER_LABEL_PREFIX__) \
"_ZNSt" _LIBCPP_TOSTRING(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH) _LIBCPP_THREAD_ABI_NAMESPACE_STR \
- "6thread20hardware_concurrencyEv"
+ "6thread20hardware_concurrencyEv"
# endif
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned __thread_hardware_concurrency() _NOEXCEPT
>From a686d63e07d0d1096121e95b8f0e48b973e1d93b Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 22 Oct 2026 12:42:46 +0100
Subject: [PATCH 3/5] Guard with C++11+, simplify the logic
---
libcxx/CMakeLists.txt | 2 ++
libcxx/include/__config_site.in | 1 +
.../include/__thread/hardware_concurrency.h | 21 +++++--------------
.../tmp.hardware_concurrency_func.pass.cpp | 1 +
4 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index d163f0f579c39..7dc427dae77b2 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -230,6 +230,7 @@ set(LIBCXX_ABI_NAMESPACE "__${LIBCXX_ABI_VERSION}" CACHE STRING "The inline ABI
if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier, got '${LIBCXX_ABI_NAMESPACE}'.")
endif()
+string(LENGTH "${LIBCXX_ABI_NAMESPACE}" LIBCPP_ABI_NAMESPACE_LEN)
set(LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION "2" CACHE STRING
"Minimum version of the libc++ headers that are allowed to be used by binaries linked against the libc++ library. This
version must correspond to the major version of an LLVM release.")
@@ -741,6 +742,7 @@ endfunction()
# Configuration file flags =====================================================
config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION)
config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
+config_define(${LIBCPP_ABI_NAMESPACE_LEN} _LIBCPP_ABI_NAMESPACE_LEN)
config_define(${LIBCXX_ABI_FORCE_ITANIUM} _LIBCPP_ABI_FORCE_ITANIUM)
config_define(${LIBCXX_ABI_FORCE_MICROSOFT} _LIBCPP_ABI_FORCE_MICROSOFT)
config_define(${LIBCXX_ENABLE_THREADS} _LIBCPP_HAS_THREADS)
diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index e6e33a2eeb2a9..785c1562de7bd 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -11,6 +11,7 @@
#cmakedefine _LIBCPP_ABI_VERSION @_LIBCPP_ABI_VERSION@
#cmakedefine _LIBCPP_ABI_NAMESPACE @_LIBCPP_ABI_NAMESPACE@
+#cmakedefine _LIBCPP_ABI_NAMESPACE_LEN @_LIBCPP_ABI_NAMESPACE_LEN@
#cmakedefine01 _LIBCPP_ABI_FORCE_ITANIUM
#cmakedefine01 _LIBCPP_ABI_FORCE_MICROSOFT
#cmakedefine01 _LIBCPP_HAS_THREADS
diff --git a/libcxx/include/__thread/hardware_concurrency.h b/libcxx/include/__thread/hardware_concurrency.h
index c378cba66059a..0e90258159a5b 100644
--- a/libcxx/include/__thread/hardware_concurrency.h
+++ b/libcxx/include/__thread/hardware_concurrency.h
@@ -22,37 +22,26 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-#if _LIBCPP_HAS_THREADS
+#if _LIBCPP_STD_VER >= 11 && _LIBCPP_HAS_THREADS
// __thread_hardware_concurrency() has the same semantics as std::[j]thread::hardware_concurrency(), but allows querying
// this information without depending on std::thread itself. Rather than adding a new symbol to the built library, it is
// declared as an alias of std::thread::hardware_concurrency(), which has always been part of the ABI.
-# define _LIBCPP_THREAD_ABI_NAMESPACE_STR _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE)
-
# ifdef _LIBCPP_ABI_MICROSOFT
# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
- "?hardware_concurrency at thread@" _LIBCPP_THREAD_ABI_NAMESPACE_STR "@std@@SAIXZ"
+ "?hardware_concurrency at thread@" _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE) "@std@@SAIXZ"
# else
-// The Itanium mangling of a namespace name is prefixed with its length, which can't be computed by the preprocessor.
-# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___1 3
-# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___2 3
-# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH___ndk1 6
-# define _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH \
- _LIBCPP_CONCAT(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH_, _LIBCPP_ABI_NAMESPACE)
-# if _LIBCPP_THREAD_ABI_NAMESPACE_LENGTH == 0
-# error "Unknown length of _LIBCPP_ABI_NAMESPACE, add it to <__thread/hardware_concurrency.h>"
-# endif
# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
_LIBCPP_TOSTRING(__USER_LABEL_PREFIX__) \
- "_ZNSt" _LIBCPP_TOSTRING(_LIBCPP_THREAD_ABI_NAMESPACE_LENGTH) _LIBCPP_THREAD_ABI_NAMESPACE_STR \
- "6thread20hardware_concurrencyEv"
+ "_ZNSt" _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE_LEN) \
+ _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE) "6thread20hardware_concurrencyEv"
# endif
[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned __thread_hardware_concurrency() _NOEXCEPT
__asm__(_LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL);
-#endif // _LIBCPP_HAS_THREADS
+#endif // _LIBCPP_STD_VER >= 11 && _LIBCPP_HAS_THREADS
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
index e380b4470ecc3..0b4ad0b69aaf3 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03
// <thread>
>From fcff7eb71eb6c3571fb882ab5f9d4112fc50e8bf Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 24 Oct 2026 10:49:17 +0100
Subject: [PATCH 4/5] Removed the temporary added test
---
.../include/__thread/hardware_concurrency.h | 4 +--
.../tmp.hardware_concurrency_func.pass.cpp | 28 -------------------
2 files changed, 2 insertions(+), 30 deletions(-)
delete mode 100644 libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
diff --git a/libcxx/include/__thread/hardware_concurrency.h b/libcxx/include/__thread/hardware_concurrency.h
index 0e90258159a5b..9fba8a30fba0c 100644
--- a/libcxx/include/__thread/hardware_concurrency.h
+++ b/libcxx/include/__thread/hardware_concurrency.h
@@ -25,8 +25,8 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 11 && _LIBCPP_HAS_THREADS
// __thread_hardware_concurrency() has the same semantics as std::[j]thread::hardware_concurrency(), but allows querying
-// this information without depending on std::thread itself. Rather than adding a new symbol to the built library, it is
-// declared as an alias of std::thread::hardware_concurrency(), which has always been part of the ABI.
+// this information without depending on std::thread itself. This function is an alias to
+// std::thread::hardware_concurrency(), which is a part of the ABI.
# ifdef _LIBCPP_ABI_MICROSOFT
# define _LIBCPP_THREAD_HARDWARE_CONCURRENCY_SYMBOL \
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
deleted file mode 100644
index 0b4ad0b69aaf3..0000000000000
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.static/tmp.hardware_concurrency_func.pass.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// UNSUPPORTED: c++03
-
-// <thread>
-
-// class thread
-
-// unsigned hardware_concurrency();
-
-#include <thread>
-#include <__thread/hardware_concurrency.h>
-#include <cassert>
-
-#include "test_macros.h"
-
-int main(int, char**) {
- assert(std::thread::hardware_concurrency() == std::__thread_hardware_concurrency());
-
- return 0;
-}
>From f19aaed03292e03e156f15d95898396c17089af5 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 24 Oct 2026 10:54:43 +0100
Subject: [PATCH 5/5] Removed the no longer used include
---
libcxx/include/__thread/thread.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index 42427cb63269f..4fd51c12a6dc2 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -22,7 +22,6 @@
#include <__memory/unique_ptr.h>
#include <__mutex/mutex.h>
#include <__system_error/throw_system_error.h>
-#include <__thread/hardware_concurrency.h>
#include <__thread/id.h>
#include <__thread/support.h>
#include <__type_traits/decay.h>
More information about the libcxx-commits
mailing list