[libc-commits] [libc] [libc] Add an extension macro to get numerical thread id (PR #195202)
via libc-commits
libc-commits at lists.llvm.org
Tue May 5 09:23:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Alexey Samsonov (vonosmas)
<details>
<summary>Changes</summary>
Adds LLVM libc extension macro: `__PTHREAD_GET_ID` (for pthreads) and `__THRD_GET_ID` (for C11 threads) that extracts integral value representation of "thread ID" from opaque `pthread_t` / `thrd_t` standard-required types.
The idea is to use this extension in libc++ code to provide llvm-libc-specific defines for `__libcpp_thread_t` internal type, which needs to support `operator==`, `operator<`, as well as zero assignment.
These are implemented as macros - making a middle ground between:
* not providing any API at all (then libc++ code would need to call `reinterpret_cast<uintptr_t>((t).__attrib)` itself, depending on private llvm-libc specific definition (as it does for zOS version of pthread_t)
* creating an actual function like `__pthread_get_thread_id(pthread_t)` that would give better type safety and diagnostics, but would result in more boilerplate code and lack of inlining opportunities
I'd be happy to switch to the latter if preferred.
Anyway, let me know what you think!
FWIW, this issue seems to be the last remaining blocker preventing us from _compiling_ libc++ against llvm-libc headers with pthread support enabled, now that @<!-- -->SchrodingerZhu has implemented `pthread_cond_` variants. It would likely not be enough to pass the test suite yet.
---
Full diff: https://github.com/llvm/llvm-project/pull/195202.diff
12 Files Affected:
- (modified) libc/include/CMakeLists.txt (+1)
- (modified) libc/include/llvm-libc-macros/CMakeLists.txt (+9)
- (modified) libc/include/llvm-libc-macros/pthread-macros.h (+7)
- (added) libc/include/llvm-libc-macros/threads-macros.h (+19)
- (modified) libc/include/pthread.yaml (+2)
- (modified) libc/include/threads.yaml (+2)
- (modified) libc/test/include/CMakeLists.txt (+13)
- (added) libc/test/include/pthread_test.c (+18)
- (modified) libc/test/integration/src/pthread/pthread_create_test.cpp (+1)
- (modified) libc/test/integration/src/pthread/pthread_equal_test.cpp (+5)
- (modified) libc/test/integration/src/threads/thrd_equal_test.cpp (+5)
- (modified) libc/test/integration/src/threads/thrd_test.cpp (+1)
``````````diff
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index aa3791b2ead2c..452f43ce91efe 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -323,6 +323,7 @@ add_header_macro(
threads.h
DEPENDS
.llvm_libc_common_h
+ .llvm-libc-macros.threads_macros
.llvm-libc-types.__call_once_func_t
.llvm-libc-types.once_flag
.llvm-libc-types.cnd_t
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 86085b50d4c4c..b2ac0d3958e22 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -386,6 +386,7 @@ add_macro_header(
pthread-macros.h
DEPENDS
.null_macro
+ .stdint_macros
)
add_macro_header(
@@ -406,6 +407,14 @@ add_macro_header(
sysexits-macros.h
)
+add_macro_header(
+ threads_macros
+ HDR
+ threads-macros.h
+ DEPENDS
+ .stdint_macros
+)
+
if (LIBC_CONF_MODULAR_FORMAT)
add_macro_header(
_LIBC_MODULAR_FORMAT_PRINTF
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 1619ad123d2c1..ffc5d282321c7 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -9,6 +9,9 @@
#ifndef LLVM_LIBC_MACROS_PTHREAD_MACRO_H
#define LLVM_LIBC_MACROS_PTHREAD_MACRO_H
+#include "__llvm-libc-common.h"
+#include "stdint-macros.h"
+
#define PTHREAD_NULL {0}
#define PTHREAD_CREATE_JOINABLE 0
@@ -77,4 +80,8 @@
#define PTHREAD_RWLOCK_PREFER_WRITER_NP 1
#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 2
+// LLVM libc extensions
+#define __PTHREAD_GET_ID(t) \
+ __LLVM_LIBC_CAST(reinterpret_cast, uintptr_t, (t).__attrib)
+
#endif // LLVM_LIBC_MACROS_PTHREAD_MACRO_H
diff --git a/libc/include/llvm-libc-macros/threads-macros.h b/libc/include/llvm-libc-macros/threads-macros.h
new file mode 100644
index 0000000000000..786efbb79cd9f
--- /dev/null
+++ b/libc/include/llvm-libc-macros/threads-macros.h
@@ -0,0 +1,19 @@
+//===-- Definition of threads macros --------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_THREADS_MACRO_H
+#define LLVM_LIBC_MACROS_THREADS_MACRO_H
+
+#include "__llvm-libc-common.h"
+#include "stdint-macros.h"
+
+// LLVM libc extensions
+#define __THRD_GET_ID(t) \
+ __LLVM_LIBC_CAST(reinterpret_cast, uintptr_t, (t).__attrib)
+
+#endif // LLVM_LIBC_MACROS_THREADS_MACRO_H
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index bb735780ab555..8f7a8e03b82c5 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -50,6 +50,8 @@ macros:
standards:
- gnu
macro_header: pthread-macros.h
+ - macro_name: __PTHREAD_GET_ID
+ macro_header: pthread-macros.h
types:
- type_name: pthread_t
- type_name: pthread_once_t
diff --git a/libc/include/threads.yaml b/libc/include/threads.yaml
index 6f7796e090ab6..67df046005bc1 100644
--- a/libc/include/threads.yaml
+++ b/libc/include/threads.yaml
@@ -4,6 +4,8 @@ standards:
macros:
- macro_name: ONCE_FLAG_INIT
macro_value: '{0}'
+ - macro_name: __THRD_GET_ID
+ macro_header: threads-macros.h
types:
- type_name: once_flag
- type_name: __call_once_func_t
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
index 85915f5a2fbda..3244a59d72e04 100644
--- a/libc/test/include/CMakeLists.txt
+++ b/libc/test/include/CMakeLists.txt
@@ -228,6 +228,19 @@ add_libc_test(
libc.include.llvm-libc-macros.netinet_in_macros
)
+add_libc_test(
+ pthread_test
+ C_TEST
+ UNIT_TEST_ONLY
+ SUITE
+ libc_include_tests
+ SRCS
+ pthread_test.c
+ DEPENDS
+ libc.include.llvm-libc-macros.pthread_macros
+ libc.include.llvm-libc-types.pthread_t
+)
+
add_libc_test(
signbit_test
SUITE
diff --git a/libc/test/include/pthread_test.c b/libc/test/include/pthread_test.c
new file mode 100644
index 0000000000000..fd6f5328e6ac5
--- /dev/null
+++ b/libc/test/include/pthread_test.c
@@ -0,0 +1,18 @@
+//===-- Unittests for pthread macro ---------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#include "include/llvm-libc-macros/pthread-macros.h"
+#include "include/llvm-libc-types/pthread_t.h"
+
+#include <assert.h>
+
+pthread_t p = PTHREAD_NULL;
+
+int main(void) {
+ assert(__PTHREAD_GET_ID(p) == 0);
+ return 0;
+}
diff --git a/libc/test/integration/src/pthread/pthread_create_test.cpp b/libc/test/integration/src/pthread/pthread_create_test.cpp
index a067a829e039b..a1e3182468142 100644
--- a/libc/test/integration/src/pthread/pthread_create_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_create_test.cpp
@@ -179,6 +179,7 @@ static void run_success_config(int detachstate, size_t guardsize,
ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&tid, attr, successThread,
reinterpret_cast<void *>(th_arg)),
0);
+ ASSERT_NE(__PTHREAD_GET_ID(tid), 0);
ASSERT_ERRNO_SUCCESS();
if (detachstate == PTHREAD_CREATE_JOINABLE) {
diff --git a/libc/test/integration/src/pthread/pthread_equal_test.cpp b/libc/test/integration/src/pthread/pthread_equal_test.cpp
index 01569798537e3..ccc3087600408 100644
--- a/libc/test/integration/src/pthread/pthread_equal_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_equal_test.cpp
@@ -21,12 +21,14 @@
pthread_t child_thread;
pthread_mutex_t mutex;
+uintptr_t child_self_thread_id;
static void *child_func(void *arg) {
LIBC_NAMESPACE::pthread_mutex_lock(&mutex);
int *ret = reinterpret_cast<int *>(arg);
auto self = LIBC_NAMESPACE::pthread_self();
*ret = LIBC_NAMESPACE::pthread_equal(child_thread, self);
+ child_self_thread_id = __PTHREAD_GET_ID(self);
LIBC_NAMESPACE::pthread_mutex_unlock(&mutex);
return nullptr;
}
@@ -50,10 +52,12 @@ TEST_MAIN() {
0);
// This new thread should of course not be equal to the main thread.
ASSERT_EQ(LIBC_NAMESPACE::pthread_equal(th, main_thread), 0);
+ ASSERT_NE(__PTHREAD_GET_ID(th), __PTHREAD_GET_ID(main_thread));
// Set the |child_thread| global var and unlock to allow the child to perform
// the comparison.
child_thread = th;
+ uintptr_t child_thread_id = __PTHREAD_GET_ID(child_thread);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex), 0);
void *retval;
@@ -62,6 +66,7 @@ TEST_MAIN() {
// The child thread should see that pthread_self return value is the same as
// |child_thread|.
ASSERT_NE(result, 0);
+ ASSERT_EQ(child_thread_id, child_self_thread_id);
LIBC_NAMESPACE::pthread_mutex_destroy(&mutex);
return 0;
diff --git a/libc/test/integration/src/threads/thrd_equal_test.cpp b/libc/test/integration/src/threads/thrd_equal_test.cpp
index 4f8866f088b92..509e258448f1e 100644
--- a/libc/test/integration/src/threads/thrd_equal_test.cpp
+++ b/libc/test/integration/src/threads/thrd_equal_test.cpp
@@ -21,12 +21,14 @@
thrd_t child_thread;
mtx_t mutex;
+uintptr_t child_self_thread_id;
static int child_func(void *arg) {
LIBC_NAMESPACE::mtx_lock(&mutex);
int *ret = reinterpret_cast<int *>(arg);
auto self = LIBC_NAMESPACE::thrd_current();
*ret = LIBC_NAMESPACE::thrd_equal(child_thread, self);
+ child_self_thread_id = __THRD_GET_ID(self);
LIBC_NAMESPACE::mtx_unlock(&mutex);
return 0;
}
@@ -50,10 +52,12 @@ TEST_MAIN() {
int(thrd_success));
// This new thread should of course not be equal to the main thread.
ASSERT_EQ(LIBC_NAMESPACE::thrd_equal(th, main_thread), 0);
+ ASSERT_NE(__THRD_GET_ID(th), __THRD_GET_ID(main_thread));
// Set the |child_thread| global var and unlock to allow the child to perform
// the comparison.
child_thread = th;
+ uintptr_t child_thread_id = __THRD_GET_ID(child_thread);
ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&mutex), int(thrd_success));
int retval;
@@ -62,6 +66,7 @@ TEST_MAIN() {
// The child thread should see that thrd_current return value is the same as
// |child_thread|.
ASSERT_NE(result, 0);
+ ASSERT_EQ(child_thread_id, child_self_thread_id);
LIBC_NAMESPACE::mtx_destroy(&mutex);
return 0;
diff --git a/libc/test/integration/src/threads/thrd_test.cpp b/libc/test/integration/src/threads/thrd_test.cpp
index 58728366b53ee..9f701224cc212 100644
--- a/libc/test/integration/src/threads/thrd_test.cpp
+++ b/libc/test/integration/src/threads/thrd_test.cpp
@@ -27,6 +27,7 @@ void create_and_join() {
ASSERT_EQ(LIBC_NAMESPACE::thrd_create(&thread, thread_func, nullptr),
(int)thrd_success);
int retval = thread_count + 1; // Start with a retval we dont expect.
+ ASSERT_NE(__THRD_GET_ID(thread), 0);
ASSERT_EQ(LIBC_NAMESPACE::thrd_join(thread, &retval), (int)thrd_success);
ASSERT_EQ(retval, 0);
ASSERT_EQ(counter, old_counter_val + 1);
``````````
</details>
https://github.com/llvm/llvm-project/pull/195202
More information about the libc-commits
mailing list