[libc-commits] [libc] [libc] Refactor thread.h (PR #216943)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Wed Aug 19 00:12:24 PDT 2026


https://github.com/labath updated https://github.com/llvm/llvm-project/pull/216943

>From 589460f3d3cf39e91b39e490f1d49689ccb9a1ca Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 12 Aug 2026 19:01:59 +0000
Subject: [PATCH 1/2] [libc] Refactor thread.h

- extract ThreadAttributes and related types into a separate header.
  This is to allow it to be referenced from other places (like the
  thread control block structure I am planning to introduce) without
  pulling in the higher level dependencies and without circular
  includes.
- move `self` into the internal namespace and provide a
  `current_thread()` accessor, preparing the code to store the thread
  pointer inside the thread control block.
---
 libc/src/__support/threads/CMakeLists.txt     |  14 +++
 libc/src/__support/threads/identifier.h       |   2 +-
 libc/src/__support/threads/linux/thread.cpp   |  21 ++--
 libc/src/__support/threads/thread.h           | 102 +--------------
 .../src/__support/threads/thread_attributes.h | 116 ++++++++++++++++++
 libc/src/pthread/pthread_getthreadid_np.cpp   |   2 +-
 libc/src/pthread/pthread_self.cpp             |   2 +-
 libc/src/stdlib/exit.cpp                      |   2 +-
 libc/src/threads/thrd_current.cpp             |   2 +-
 libc/startup/linux/do_start.cpp               |   2 +-
 10 files changed, 152 insertions(+), 113 deletions(-)
 create mode 100644 libc/src/__support/threads/thread_attributes.h

diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index 100346a84b7c2..67a176f87a9fd 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -19,6 +19,19 @@ add_header_library(
     libc.src.__support.CPP.atomic
 )
 
+add_header_library(
+  thread_attributes
+  HDRS
+    thread_attributes.h
+  DEPENDS
+    libc.hdr.stdint_proxy
+    libc.hdr.types.size_t
+    libc.src.__support.CPP.atomic
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+    libc.src.__support.macros.properties.architectures
+)
+
 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
   add_subdirectory(${LIBC_TARGET_OS})
 endif()
@@ -111,6 +124,7 @@ add_header_library(
   HDRS
     thread.h
   DEPENDS
+    .thread_attributes
     libc.hdr.stdint_proxy
     libc.hdr.types.struct_sched_param
     libc.src.__support.common
diff --git a/libc/src/__support/threads/identifier.h b/libc/src/__support/threads/identifier.h
index a570abfd5dc73..dfc5bf41edc17 100644
--- a/libc/src/__support/threads/identifier.h
+++ b/libc/src/__support/threads/identifier.h
@@ -23,7 +23,7 @@ namespace internal {
 
 LIBC_INLINE pid_t *get_tid_cache() {
 #ifdef LIBC_FULL_BUILD
-  return &self.attrib->tid;
+  return &current_thread().attrib->tid;
 #else
   // in non-full build mode, we do not control the fork routine. Therefore,
   // we do not cache tid at all.
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 9142d8ff10b00..231b7cf2903ca 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -180,8 +180,8 @@ cleanup_thread_resources(ThreadAttributes *attrib) {
 [[gnu::noinline]] void start_thread() {
   auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr());
   auto *attrib = start_args->thread_attrib;
-  self.attrib = attrib;
-  self.attrib->atexit_callback_mgr = internal::get_thread_atexit_callback_mgr();
+  internal::self.attrib = attrib;
+  attrib->atexit_callback_mgr = internal::get_thread_atexit_callback_mgr();
 
   if (attrib->style == ThreadStyle::POSIX) {
     attrib->retval.posix_retval =
@@ -342,21 +342,22 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
 }
 
 int Thread::join(ThreadReturnValue &retval) {
-  if (self.attrib) {
+  if (current_thread().attrib) {
     // Reject self join.
-    if (self.attrib == attrib)
+    if (current_thread().attrib == attrib)
       return EDEADLK;
 
     // Do a best-effort check of concurrent/repeated join.
     // This cmpxchg establishes exclusive joiner role by setting the joiner
     // field iff there is no previous joiner
     ThreadAttributes *expected = nullptr;
-    if (!attrib->joiner.compare_exchange_strong(expected, self.attrib,
-                                                cpp::MemoryOrder::ACQ_REL))
+    if (!attrib->joiner.compare_exchange_strong(
+            expected, current_thread().attrib, cpp::MemoryOrder::ACQ_REL))
       return EINVAL;
 
     // Reject mutual join.
-    if (self.attrib->joiner.load(cpp::MemoryOrder::ACQUIRE) == attrib) {
+    if (current_thread().attrib->joiner.load(cpp::MemoryOrder::ACQUIRE) ==
+        attrib) {
       attrib->joiner.store(nullptr, cpp::MemoryOrder::RELEASE);
       return EDEADLK;
     }
@@ -423,7 +424,7 @@ int Thread::set_name(const cpp::string_view &name) {
   if (name.size() >= NAME_SIZE_MAX)
     return ERANGE;
 
-  if (*this == self) {
+  if (*this == current_thread()) {
     // If we are setting the name of the current thread, then we can
     // use the syscall to set the name.
     int retval =
@@ -459,7 +460,7 @@ int Thread::get_name(cpp::StringStream &name) const {
 
   char name_buffer[NAME_SIZE_MAX];
 
-  if (*this == self) {
+  if (*this == current_thread()) {
     // If we are getting the name of the current thread, then we can
     // use the syscall to get the name.
     int retval =
@@ -515,7 +516,7 @@ ErrorOr<SchedParameters> Thread::getschedparam() const {
 }
 
 void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
-  auto attrib = self.attrib;
+  auto attrib = current_thread().attrib;
 
   // The very first thing we do is to call the thread's atexit callbacks.
   // These callbacks could be the ones registered by the language runtimes,
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index ac6b6ce6fb967..c42f87a1a3c57 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -19,12 +19,11 @@
 #include "src/__support/macros/attributes.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/architectures.h"
+#include "src/__support/threads/thread_attributes.h"
 
 // TODO: fix this unguarded linux dep
 #include <linux/param.h> // for exec_pagesize.
 
-#include <stddef.h> // For size_t
-
 namespace LIBC_NAMESPACE_DECL {
 
 struct SchedParameters {
@@ -32,99 +31,6 @@ struct SchedParameters {
   struct sched_param param;
 };
 
-using ThreadRunnerPosix = void *(void *);
-using ThreadRunnerStdc = int(void *);
-
-union ThreadRunner {
-  ThreadRunnerPosix *posix_runner;
-  ThreadRunnerStdc *stdc_runner;
-};
-
-union ThreadReturnValue {
-  void *posix_retval;
-  int stdc_retval;
-  constexpr ThreadReturnValue() : posix_retval(nullptr) {}
-  constexpr ThreadReturnValue(int r) : stdc_retval(r) {}
-  constexpr ThreadReturnValue(void *r) : posix_retval(r) {}
-};
-
-#if (defined(LIBC_TARGET_ARCH_IS_AARCH64) ||                                   \
-     defined(LIBC_TARGET_ARCH_IS_X86_64) ||                                    \
-     defined(LIBC_TARGET_ARCH_IS_ANY_RISCV))
-constexpr unsigned int STACK_ALIGNMENT = 16;
-#elif defined(LIBC_TARGET_ARCH_IS_ARM)
-// See Section 6.2.1.2 Stack constraints at a public interface of AAPCS32.
-constexpr unsigned int STACK_ALIGNMENT = 8;
-#endif
-// TODO: Provide stack alignment requirements for other architectures.
-
-enum class DetachState : uint32_t {
-  JOINABLE = 0x11,
-  EXITING = 0x22,
-  DETACHED = 0x33
-};
-
-enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 };
-
-// Detach type is useful in testing the detach operation.
-enum class DetachType : int {
-  // Indicates that the detach operation just set the detach state to DETACHED
-  // and returned.
-  SIMPLE = 1,
-
-  // Indicates that the detach operation performed thread cleanup.
-  CLEANUP = 2
-};
-
-class ThreadAtExitCallbackMgr;
-
-// A data type to hold common thread attributes which have to be stored as
-// thread state. Note that this is different from public attribute types like
-// pthread_attr_t which might contain information which need not be saved as
-// part of a thread's state. For example, the stack guard size.
-//
-// Thread attributes are typically stored on the stack. So, we align as required
-// for the target architecture.
-struct alignas(STACK_ALIGNMENT) ThreadAttributes {
-  // We want the "detach_state" attribute to be an atomic value as it could be
-  // updated by one thread while the self thread is reading it. It is a tristate
-  // variable with the following state transitions:
-  // 1. The a thread is created in a detached state, then user code should never
-  //    call a detach or join function. Calling either of them can lead to
-  //    undefined behavior.
-  //    The value of |detach_state| is expected to be DetachState::DETACHED for
-  //    its lifetime.
-  // 2. If a thread is created in a joinable state, |detach_state| will start
-  //    with the value DetachState::JOINABLE. Another thread can detach this
-  //    thread before it exits. The state transitions will as follows:
-  //      (a) If the detach method sees the state as JOINABLE, then it will
-  //          compare exchange to a state of DETACHED. The thread will clean
-  //          itself up after it finishes.
-  //      (b) If the detach method does not see JOINABLE in (a), then it will
-  //          conclude that the thread is EXITING and will wait until the thread
-  //          exits. It will clean up the thread resources once the thread
-  //          exits.
-  cpp::Atomic<uint32_t> detach_state;
-  void *stack;               // Pointer to the thread stack
-  size_t stacksize;          // Size of the stack
-  size_t guardsize;          // Guard size on stack
-  uintptr_t tls;             // Address to the thread TLS memory
-  uintptr_t tls_size;        // The size of area pointed to by |tls|.
-  unsigned char owned_stack; // Indicates if the thread owns this stack memory
-  int tid;
-  ThreadStyle style;
-  ThreadReturnValue retval;
-  ThreadAtExitCallbackMgr *atexit_callback_mgr;
-  void *platform_data;
-  cpp::Atomic<ThreadAttributes *> joiner;
-
-  LIBC_INLINE constexpr ThreadAttributes()
-      : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr),
-        stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false),
-        tid(-1), style(ThreadStyle::POSIX), retval(),
-        atexit_callback_mgr(nullptr), platform_data(nullptr), joiner(nullptr) {}
-};
-
 using TSSDtor = void(void *);
 
 // Create a new TSS key and associate the |dtor| as the corresponding
@@ -247,8 +153,6 @@ struct Thread {
   ErrorOr<SchedParameters> getschedparam() const;
 };
 
-LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;
-
 // Platforms should implement this function.
 [[noreturn]] void thread_exit(ThreadReturnValue retval, ThreadStyle style);
 
@@ -266,8 +170,12 @@ ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr();
 // implementing the thread_exit function.
 void call_atexit_callbacks(ThreadAttributes *attrib);
 
+LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;
+
 } // namespace internal
 
+LIBC_INLINE Thread current_thread() { return internal::self; }
+
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
diff --git a/libc/src/__support/threads/thread_attributes.h b/libc/src/__support/threads/thread_attributes.h
new file mode 100644
index 0000000000000..85befdc51f5d5
--- /dev/null
+++ b/libc/src/__support/threads/thread_attributes.h
@@ -0,0 +1,116 @@
+//===-- Common thread attributes --------------------------------*- 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___SUPPORT_THREADS_THREAD_ATTRIBUTES_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_ATTRIBUTES_H
+
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/atomic.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using ThreadRunnerPosix = void *(void *);
+using ThreadRunnerStdc = int(void *);
+
+union ThreadRunner {
+  ThreadRunnerPosix *posix_runner;
+  ThreadRunnerStdc *stdc_runner;
+};
+
+union ThreadReturnValue {
+  void *posix_retval;
+  int stdc_retval;
+  LIBC_INLINE constexpr ThreadReturnValue() : posix_retval(nullptr) {}
+  LIBC_INLINE constexpr ThreadReturnValue(int r) : stdc_retval(r) {}
+  LIBC_INLINE constexpr ThreadReturnValue(void *r) : posix_retval(r) {}
+};
+
+#if (defined(LIBC_TARGET_ARCH_IS_AARCH64) ||                                   \
+     defined(LIBC_TARGET_ARCH_IS_X86_64) ||                                    \
+     defined(LIBC_TARGET_ARCH_IS_ANY_RISCV))
+constexpr unsigned int STACK_ALIGNMENT = 16;
+#elif defined(LIBC_TARGET_ARCH_IS_ARM)
+// See Section 6.2.1.2 Stack constraints at a public interface of AAPCS32.
+constexpr unsigned int STACK_ALIGNMENT = 8;
+#endif
+// TODO: Provide stack alignment requirements for other architectures.
+
+enum class DetachState : uint32_t {
+  JOINABLE = 0x11,
+  EXITING = 0x22,
+  DETACHED = 0x33
+};
+
+enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 };
+
+// Detach type is useful in testing the detach operation.
+enum class DetachType : int {
+  // Indicates that the detach operation just set the detach state to DETACHED
+  // and returned.
+  SIMPLE = 1,
+
+  // Indicates that the detach operation performed thread cleanup.
+  CLEANUP = 2
+};
+
+class ThreadAtExitCallbackMgr;
+
+// A data type to hold common thread attributes which have to be stored as
+// thread state. Note that this is different from public attribute types like
+// pthread_attr_t which might contain information which need not be saved as
+// part of a thread's state. For example, the stack guard size.
+//
+// Thread attributes are typically stored on the stack. So, we align as required
+// for the target architecture.
+struct alignas(STACK_ALIGNMENT) ThreadAttributes {
+  // We want the "detach_state" attribute to be an atomic value as it could be
+  // updated by one thread while the self thread is reading it. It is a tristate
+  // variable with the following state transitions:
+  // 1. If a thread is created in a detached state, then user code should never
+  //    call a detach or join function. Calling either of them can lead to
+  //    undefined behavior.
+  //    The value of |detach_state| is expected to be DetachState::DETACHED for
+  //    its lifetime.
+  // 2. If a thread is created in a joinable state, |detach_state| will start
+  //    with the value DetachState::JOINABLE. Another thread can detach this
+  //    thread before it exits. The state transitions will as follows:
+  //      (a) If the detach method sees the state as JOINABLE, then it will
+  //          compare exchange to a state of DETACHED. The thread will clean
+  //          itself up after it finishes.
+  //      (b) If the detach method does not see JOINABLE in (a), then it will
+  //          conclude that the thread is EXITING and will wait until the thread
+  //          exits. It will clean up the thread resources once the thread
+  //          exits.
+  cpp::Atomic<uint32_t> detach_state;
+  void *stack;               // Pointer to the thread stack
+  size_t stacksize;          // Size of the stack
+  size_t guardsize;          // Guard size on stack
+  uintptr_t tls;             // Address to the thread TLS memory
+  uintptr_t tls_size;        // The size of area pointed to by |tls|.
+  unsigned char owned_stack; // Indicates if the thread owns this stack memory
+  int tid;
+  ThreadStyle style;
+  ThreadReturnValue retval;
+  ThreadAtExitCallbackMgr *atexit_callback_mgr;
+  void *platform_data;
+  cpp::Atomic<ThreadAttributes *> joiner;
+
+  LIBC_INLINE constexpr ThreadAttributes()
+      : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr),
+        stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false),
+        tid(-1), style(ThreadStyle::POSIX), retval(),
+        atexit_callback_mgr(nullptr), platform_data(nullptr), joiner(nullptr) {}
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_ATTRIBUTES_H
diff --git a/libc/src/pthread/pthread_getthreadid_np.cpp b/libc/src/pthread/pthread_getthreadid_np.cpp
index 4fa9b7cc1166f..d44a6341fd215 100644
--- a/libc/src/pthread/pthread_getthreadid_np.cpp
+++ b/libc/src/pthread/pthread_getthreadid_np.cpp
@@ -21,7 +21,7 @@ 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);
+  return reinterpret_cast<pthread_id_np_t>(current_thread().attrib);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_self.cpp b/libc/src/pthread/pthread_self.cpp
index c3169ec1ca5c4..2f72d15f99435 100644
--- a/libc/src/pthread/pthread_self.cpp
+++ b/libc/src/pthread/pthread_self.cpp
@@ -21,7 +21,7 @@ static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
 
 LLVM_LIBC_FUNCTION(pthread_t, pthread_self, ()) {
   pthread_t th;
-  th.__attrib = self.attrib;
+  th.__attrib = current_thread().attrib;
   return th;
 }
 
diff --git a/libc/src/stdlib/exit.cpp b/libc/src/stdlib/exit.cpp
index 580519237761a..99763729cf5b4 100644
--- a/libc/src/stdlib/exit.cpp
+++ b/libc/src/stdlib/exit.cpp
@@ -23,7 +23,7 @@ extern "C" void __cxa_finalize(void *);
 [[noreturn]] LLVM_LIBC_FUNCTION(void, exit, (int status)) {
 #ifdef LIBC_COPT_SUPPORT_THREADS
   // Call TLS destructors, if supported by the target.
-  internal::call_atexit_callbacks(self.attrib);
+  internal::call_atexit_callbacks(current_thread().attrib);
 #endif
   __cxa_finalize(nullptr);
   internal::exit(status);
diff --git a/libc/src/threads/thrd_current.cpp b/libc/src/threads/thrd_current.cpp
index 634159712b629..0090195364861 100644
--- a/libc/src/threads/thrd_current.cpp
+++ b/libc/src/threads/thrd_current.cpp
@@ -20,7 +20,7 @@ static_assert(sizeof(thrd_t) == sizeof(LIBC_NAMESPACE::Thread),
 
 LLVM_LIBC_FUNCTION(thrd_t, thrd_current, ()) {
   thrd_t th;
-  th.__attrib = self.attrib;
+  th.__attrib = current_thread().attrib;
   return th;
 }
 
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index 85f46a8e97fcf..5c6733921a601 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -182,7 +182,7 @@ static TLSDescriptor tls;
   if (tls.size != 0 && !set_thread_ptr(tls.tp))
     syscall_impl<long>(SYS_exit, 1);
 
-  self.attrib = &main_thread_attrib;
+  internal::self.attrib = &main_thread_attrib;
   main_thread_attrib.atexit_callback_mgr =
       internal::get_thread_atexit_callback_mgr();
 

>From 0a6e810b8573af15a8637dd531cf62b6b098ab66 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 19 Aug 2026 07:12:04 +0000
Subject: [PATCH 2/2] fix file header

---
 libc/src/__support/threads/thread_attributes.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/threads/thread_attributes.h b/libc/src/__support/threads/thread_attributes.h
index 85befdc51f5d5..6225837ed7784 100644
--- a/libc/src/__support/threads/thread_attributes.h
+++ b/libc/src/__support/threads/thread_attributes.h
@@ -1,10 +1,15 @@
-//===-- Common thread attributes --------------------------------*- 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
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// Common thread attributes.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_ATTRIBUTES_H
 #define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_ATTRIBUTES_H



More information about the libc-commits mailing list