[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 ¤t_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