[libc-commits] [libc] [libc] Implement pthread_getthreadid_np and pthread_getunique_np. (PR #197027)
Alexey Samsonov via libc-commits
libc-commits at lists.llvm.org
Mon May 11 13:05:29 PDT 2026
https://github.com/vonosmas created https://github.com/llvm/llvm-project/pull/197027
This is an alternative to https://github.com/llvm/llvm-project/pull/195202 which uses @petrhosek 's suggestion
to use an existing `pthread_getthreadid_np()` instead.
We define two functions:
* pthread_getthreadid_np - to return a thread-id for the current thread. **NOTE:** We're using the IBM variant of this function (https://www.ibm.com/docs/en/i/7.6.0?topic=ssw_ibm_i_76/apis/users_22.html) instead of FreeBSD one (https://man.freebsd.org/cgi/man.cgi?pthread_getthreadid_np), so that we can return a more-opaque integral type (in our case - `uintptr_t` rather than `int`).
* pthread_getunique_np - it's even less standard one. We're also using IBM variant here (https://www.ibm.com/docs/en/i/7.6.0?topic=ssw_ibm_i_76/apis/users_23.html). This one is needed because we need to have the capability to convert `pthread_t` into a numeric ID.
>From c09a903b900a04f388f94c67420b1569c10f3613 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Mon, 11 May 2026 19:33:19 +0000
Subject: [PATCH] [libc] Implement pthread_getthreadid_np and
pthread_getunique_np.
---
libc/config/linux/aarch64/entrypoints.txt | 2 ++
libc/config/linux/riscv/entrypoints.txt | 2 ++
libc/config/linux/x86_64/entrypoints.txt | 2 ++
libc/include/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
.../include/llvm-libc-types/pthread_id_np_t.h | 16 ++++++++++
libc/include/pthread.yaml | 10 +++++++
libc/src/pthread/CMakeLists.txt | 22 ++++++++++++++
libc/src/pthread/pthread_getthreadid_np.cpp | 24 +++++++++++++++
libc/src/pthread/pthread_getthreadid_np.h | 21 ++++++++++++++
libc/src/pthread/pthread_getunique_np.cpp | 29 +++++++++++++++++++
libc/src/pthread/pthread_getunique_np.h | 21 ++++++++++++++
.../integration/src/pthread/CMakeLists.txt | 3 ++
.../src/pthread/pthread_create_test.cpp | 4 +++
.../src/pthread/pthread_equal_test.cpp | 9 ++++++
15 files changed, 167 insertions(+)
create mode 100644 libc/include/llvm-libc-types/pthread_id_np_t.h
create mode 100644 libc/src/pthread/pthread_getthreadid_np.cpp
create mode 100644 libc/src/pthread/pthread_getthreadid_np.h
create mode 100644 libc/src/pthread/pthread_getunique_np.cpp
create mode 100644 libc/src/pthread/pthread_getunique_np.h
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9994a9294173d..d1c79321c80ab 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1038,6 +1038,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_getname_np
libc.src.pthread.pthread_getspecific
+ libc.src.pthread.pthread_getthreadid_np
+ libc.src.pthread.pthread_getunique_np
libc.src.pthread.pthread_join
libc.src.pthread.pthread_key_create
libc.src.pthread.pthread_key_delete
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2748b2b8e6a5d..d561ef0eb7040 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1171,6 +1171,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_getname_np
libc.src.pthread.pthread_getspecific
+ libc.src.pthread.pthread_getthreadid_np
+ libc.src.pthread.pthread_getunique_np
libc.src.pthread.pthread_join
libc.src.pthread.pthread_key_create
libc.src.pthread.pthread_key_delete
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 4b551ced82138..1098c2560bff3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1228,6 +1228,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_getname_np
libc.src.pthread.pthread_getspecific
+ libc.src.pthread.pthread_getthreadid_np
+ libc.src.pthread.pthread_getunique_np
libc.src.pthread.pthread_join
libc.src.pthread.pthread_key_create
libc.src.pthread.pthread_key_delete
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index e5f96ab19d9f1..52fe60bc08de6 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -469,6 +469,7 @@ add_header_macro(
.llvm-libc-types.pthread_rwlockattr_t
.llvm-libc-types.pthread_spinlock_t
.llvm-libc-types.pthread_t
+ .llvm-libc-types.pthread_id_np_t
.llvm-libc-types.struct_timespec
.llvm_libc_common_h
)
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index e967b43d81df0..1edc67043395a 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -84,6 +84,7 @@ add_header(pthread_rwlock_t HDR pthread_rwlock_t.h DEPENDS .__futex_word .pid_t)
add_header(pthread_rwlockattr_t HDR pthread_rwlockattr_t.h)
add_header(pthread_spinlock_t HDR pthread_spinlock_t.h DEPENDS .pid_t)
add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type)
+add_header(pthread_id_np_t HDR pthread_id_np_t.h DEPENDS libc.include.llvm-libc-macros.stdint_macros)
add_header(rlim_t HDR rlim_t.h)
if(LIBC_TYPES_TIME_T_IS_32_BIT)
add_header(time_t HDR time_t_32.h DEST_HDR time_t.h)
diff --git a/libc/include/llvm-libc-types/pthread_id_np_t.h b/libc/include/llvm-libc-types/pthread_id_np_t.h
new file mode 100644
index 0000000000000..cfce995d69d3b
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_id_np_t.h
@@ -0,0 +1,16 @@
+//===-- Definition of pthread_id_np_t type --------------------------------===//
+//
+// 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_TYPES_PTHREAD_ID_NP_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_ID_NP_T_H
+
+#include "../llvm-libc-macros/stdint-macros.h"
+
+typedef uintptr_t pthread_id_np_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_ID_NP_T_H
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index bb735780ab555..a57c2fe4eab32 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -64,6 +64,7 @@ types:
- type_name: pthread_rwlockattr_t
- type_name: pthread_attr_t
- type_name: pthread_spinlock_t
+ - type_name: pthread_id_np_t
functions:
- name: pthread_atfork
return_type: int
@@ -444,3 +445,12 @@ functions:
return_type: int
arguments:
- type: pthread_spinlock_t *
+ - name: pthread_getthreadid_np
+ return_type: pthread_id_np_t
+ arguments:
+ - type: void
+ - name: pthread_getunique_np
+ return_type: int
+ arguments:
+ - type: pthread_t *
+ - type: pthread_id_np_t *
\ No newline at end of file
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 9b08c4c7394ff..768a41c6c9514 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -591,6 +591,28 @@ add_entrypoint_object(
libc.src.__support.threads.thread
)
+add_entrypoint_object(
+ pthread_getthreadid_np
+ SRCS
+ pthread_getthreadid_np.cpp
+ HDRS
+ pthread_getthreadid_np.h
+ DEPENDS
+ libc.include.pthread
+)
+
+add_entrypoint_object(
+ pthread_getunique_np
+ SRCS
+ pthread_getunique_np.cpp
+ HDRS
+ pthread_getunique_np.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.macros.null_check
+ libc.src.__support.threads.thread
+)
+
add_entrypoint_object(
pthread_key_create
SRCS
diff --git a/libc/src/pthread/pthread_getthreadid_np.cpp b/libc/src/pthread/pthread_getthreadid_np.cpp
new file mode 100644
index 0000000000000..68f1289a92b63
--- /dev/null
+++ b/libc/src/pthread/pthread_getthreadid_np.cpp
@@ -0,0 +1,24 @@
+//===-- Implementation of the pthread_getthreadid_np function -------------===//
+//
+// 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 "pthread_getthreadid_np.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(pthread_id_np_t, pthread_getthreadid_np, ()) {
+ // We assume that unique thread ID is an integer value of a pointer to TCB.
+ return reinterpret_cast<pthread_id_np_t>(self.attrib);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_getthreadid_np.h b/libc/src/pthread/pthread_getthreadid_np.h
new file mode 100644
index 0000000000000..521d48e90267f
--- /dev/null
+++ b/libc/src/pthread/pthread_getthreadid_np.h
@@ -0,0 +1,21 @@
+//===- Implementation header for pthread_getthreadid_np --------*- C++ -*-===//
+//
+// 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_SRC_PTHREAD_PTHREAD_GETTHREADID_NP_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETTHREADID_NP_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+pthread_id_np_t pthread_getthreadid_np();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETTHREADID_NP_H
diff --git a/libc/src/pthread/pthread_getunique_np.cpp b/libc/src/pthread/pthread_getunique_np.cpp
new file mode 100644
index 0000000000000..5dabec2c176b9
--- /dev/null
+++ b/libc/src/pthread/pthread_getunique_np.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of the pthread_getunique_np function ---------------===//
+//
+// 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 "pthread_getunique_np.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_getunique_np,
+ (pthread_t * thread, pthread_id_np_t *id)) {
+ LIBC_CRASH_ON_NULLPTR(id);
+ // We assume that unique thread ID is an integer value of a pointer to TCB.
+ *id = (thread == nullptr)
+ ? 0
+ : reinterpret_cast<pthread_id_np_t>(thread->__attrib);
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_getunique_np.h b/libc/src/pthread/pthread_getunique_np.h
new file mode 100644
index 0000000000000..1157d4ac7344c
--- /dev/null
+++ b/libc/src/pthread/pthread_getunique_np.h
@@ -0,0 +1,21 @@
+//===- Implementation header for pthread_getunique_np function --*- C++ -*-===//
+//
+// 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_SRC_PTHREAD_PTHREAD_GETUNIQUE_NP_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETUNIQUE_NP_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_getunique_np(pthread_t *thread, pthread_id_np_t *);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETUNIQUE_NP_H
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 98e5dbebbfcd1..250cc9114f13d 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -165,6 +165,8 @@ add_integration_test(
libc.src.pthread.pthread_mutex_unlock
libc.src.pthread.pthread_create
libc.src.pthread.pthread_equal
+ libc.src.pthread.pthread_getthreadid_np
+ libc.src.pthread.pthread_getunique_np
libc.src.pthread.pthread_join
libc.src.pthread.pthread_self
)
@@ -278,6 +280,7 @@ add_integration_test(
libc.src.pthread.pthread_attr_setstacksize
libc.src.pthread.pthread_attr_init
libc.src.pthread.pthread_attr_destroy
+ libc.src.pthread.pthread_getunique_np
libc.src.pthread.pthread_self
libc.src.sys.mman.mmap
libc.src.sys.mman.munmap
diff --git a/libc/test/integration/src/pthread/pthread_create_test.cpp b/libc/test/integration/src/pthread/pthread_create_test.cpp
index a067a829e039b..dd8d3ef1c8e35 100644
--- a/libc/test/integration/src/pthread/pthread_create_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_create_test.cpp
@@ -18,6 +18,7 @@
#include "src/pthread/pthread_attr_setstack.h"
#include "src/pthread/pthread_attr_setstacksize.h"
#include "src/pthread/pthread_create.h"
+#include "src/pthread/pthread_getunique_np.h"
#include "src/pthread/pthread_join.h"
#include "src/pthread/pthread_self.h"
@@ -180,6 +181,9 @@ static void run_success_config(int detachstate, size_t guardsize,
reinterpret_cast<void *>(th_arg)),
0);
ASSERT_ERRNO_SUCCESS();
+ pthread_id_np_t id;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_getunique_np(&tid, &id), 0);
+ ASSERT_NE(id, 0);
if (detachstate == PTHREAD_CREATE_JOINABLE) {
void *th_ret;
diff --git a/libc/test/integration/src/pthread/pthread_equal_test.cpp b/libc/test/integration/src/pthread/pthread_equal_test.cpp
index 01569798537e3..435065e92d698 100644
--- a/libc/test/integration/src/pthread/pthread_equal_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_equal_test.cpp
@@ -9,6 +9,8 @@
#include "hdr/stdint_proxy.h" // uintptr_t
#include "src/pthread/pthread_create.h"
#include "src/pthread/pthread_equal.h"
+#include "src/pthread/pthread_getthreadid_np.h"
+#include "src/pthread/pthread_getunique_np.h"
#include "src/pthread/pthread_join.h"
#include "src/pthread/pthread_mutex_destroy.h"
#include "src/pthread/pthread_mutex_init.h"
@@ -20,6 +22,7 @@
#include <pthread.h>
pthread_t child_thread;
+pthread_id_np_t child_self_thread_id;
pthread_mutex_t mutex;
static void *child_func(void *arg) {
@@ -27,6 +30,7 @@ static void *child_func(void *arg) {
int *ret = reinterpret_cast<int *>(arg);
auto self = LIBC_NAMESPACE::pthread_self();
*ret = LIBC_NAMESPACE::pthread_equal(child_thread, self);
+ child_self_thread_id = LIBC_NAMESPACE::pthread_getthreadid_np();
LIBC_NAMESPACE::pthread_mutex_unlock(&mutex);
return nullptr;
}
@@ -38,6 +42,7 @@ TEST_MAIN() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex), 0);
auto main_thread = LIBC_NAMESPACE::pthread_self();
+ pthread_id_np_t main_thread_id = LIBC_NAMESPACE::pthread_getthreadid_np();
// The idea here is that, we start a child thread which will immediately
// wait on |mutex|. The main thread will update the global |child_thread| var
@@ -46,10 +51,13 @@ TEST_MAIN() {
// comparison is returned in the thread arg.
int result = 0;
pthread_t th;
+ pthread_id_np_t th_id;
ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, nullptr, child_func, &result),
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_EQ(LIBC_NAMESPACE::pthread_getunique_np(&th, &th_id), 0);
+ ASSERT_NE(th_id, main_thread_id);
// Set the |child_thread| global var and unlock to allow the child to perform
// the comparison.
@@ -62,6 +70,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(th_id, child_self_thread_id);
LIBC_NAMESPACE::pthread_mutex_destroy(&mutex);
return 0;
More information about the libc-commits
mailing list