[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