xref: /freebsd/contrib/llvm-project/libc/src/__support/threads/thread.h (revision bb722a7d0f1642bff6487f943ad0427799a6e5bf)
1*bb722a7dSDimitry Andric //===--- A platform independent indirection for a thread class --*- C++ -*-===//
2*bb722a7dSDimitry Andric //
3*bb722a7dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bb722a7dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*bb722a7dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bb722a7dSDimitry Andric //
7*bb722a7dSDimitry Andric //===----------------------------------------------------------------------===//
8*bb722a7dSDimitry Andric 
9*bb722a7dSDimitry Andric #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
10*bb722a7dSDimitry Andric #define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
11*bb722a7dSDimitry Andric 
12*bb722a7dSDimitry Andric #include "src/__support/CPP/atomic.h"
13*bb722a7dSDimitry Andric #include "src/__support/CPP/optional.h"
14*bb722a7dSDimitry Andric #include "src/__support/CPP/string_view.h"
15*bb722a7dSDimitry Andric #include "src/__support/CPP/stringstream.h"
16*bb722a7dSDimitry Andric #include "src/__support/macros/attributes.h"
17*bb722a7dSDimitry Andric #include "src/__support/macros/config.h"
18*bb722a7dSDimitry Andric #include "src/__support/macros/properties/architectures.h"
19*bb722a7dSDimitry Andric 
20*bb722a7dSDimitry Andric // TODO: fix this unguarded linux dep
21*bb722a7dSDimitry Andric #include <linux/param.h> // for exec_pagesize.
22*bb722a7dSDimitry Andric 
23*bb722a7dSDimitry Andric #include <stddef.h> // For size_t
24*bb722a7dSDimitry Andric #include <stdint.h>
25*bb722a7dSDimitry Andric 
26*bb722a7dSDimitry Andric namespace LIBC_NAMESPACE_DECL {
27*bb722a7dSDimitry Andric 
28*bb722a7dSDimitry Andric using ThreadRunnerPosix = void *(void *);
29*bb722a7dSDimitry Andric using ThreadRunnerStdc = int(void *);
30*bb722a7dSDimitry Andric 
31*bb722a7dSDimitry Andric union ThreadRunner {
32*bb722a7dSDimitry Andric   ThreadRunnerPosix *posix_runner;
33*bb722a7dSDimitry Andric   ThreadRunnerStdc *stdc_runner;
34*bb722a7dSDimitry Andric };
35*bb722a7dSDimitry Andric 
36*bb722a7dSDimitry Andric union ThreadReturnValue {
37*bb722a7dSDimitry Andric   void *posix_retval;
38*bb722a7dSDimitry Andric   int stdc_retval;
ThreadReturnValue()39*bb722a7dSDimitry Andric   constexpr ThreadReturnValue() : posix_retval(nullptr) {}
ThreadReturnValue(int r)40*bb722a7dSDimitry Andric   constexpr ThreadReturnValue(int r) : stdc_retval(r) {}
ThreadReturnValue(void * r)41*bb722a7dSDimitry Andric   constexpr ThreadReturnValue(void *r) : posix_retval(r) {}
42*bb722a7dSDimitry Andric };
43*bb722a7dSDimitry Andric 
44*bb722a7dSDimitry Andric #if (defined(LIBC_TARGET_ARCH_IS_AARCH64) ||                                   \
45*bb722a7dSDimitry Andric      defined(LIBC_TARGET_ARCH_IS_X86_64) ||                                    \
46*bb722a7dSDimitry Andric      defined(LIBC_TARGET_ARCH_IS_ANY_RISCV))
47*bb722a7dSDimitry Andric constexpr unsigned int STACK_ALIGNMENT = 16;
48*bb722a7dSDimitry Andric #elif defined(LIBC_TARGET_ARCH_IS_ARM)
49*bb722a7dSDimitry Andric // See Section 6.2.1.2 Stack constraints at a public interface of AAPCS32.
50*bb722a7dSDimitry Andric constexpr unsigned int STACK_ALIGNMENT = 8;
51*bb722a7dSDimitry Andric #endif
52*bb722a7dSDimitry Andric // TODO: Provide stack alignment requirements for other architectures.
53*bb722a7dSDimitry Andric 
54*bb722a7dSDimitry Andric enum class DetachState : uint32_t {
55*bb722a7dSDimitry Andric   JOINABLE = 0x11,
56*bb722a7dSDimitry Andric   EXITING = 0x22,
57*bb722a7dSDimitry Andric   DETACHED = 0x33
58*bb722a7dSDimitry Andric };
59*bb722a7dSDimitry Andric 
60*bb722a7dSDimitry Andric enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 };
61*bb722a7dSDimitry Andric 
62*bb722a7dSDimitry Andric // Detach type is useful in testing the detach operation.
63*bb722a7dSDimitry Andric enum class DetachType : int {
64*bb722a7dSDimitry Andric   // Indicates that the detach operation just set the detach state to DETACHED
65*bb722a7dSDimitry Andric   // and returned.
66*bb722a7dSDimitry Andric   SIMPLE = 1,
67*bb722a7dSDimitry Andric 
68*bb722a7dSDimitry Andric   // Indicates that the detach operation performed thread cleanup.
69*bb722a7dSDimitry Andric   CLEANUP = 2
70*bb722a7dSDimitry Andric };
71*bb722a7dSDimitry Andric 
72*bb722a7dSDimitry Andric class ThreadAtExitCallbackMgr;
73*bb722a7dSDimitry Andric 
74*bb722a7dSDimitry Andric // A data type to hold common thread attributes which have to be stored as
75*bb722a7dSDimitry Andric // thread state. Note that this is different from public attribute types like
76*bb722a7dSDimitry Andric // pthread_attr_t which might contain information which need not be saved as
77*bb722a7dSDimitry Andric // part of a thread's state. For example, the stack guard size.
78*bb722a7dSDimitry Andric //
79*bb722a7dSDimitry Andric // Thread attributes are typically stored on the stack. So, we align as required
80*bb722a7dSDimitry Andric // for the target architecture.
81*bb722a7dSDimitry Andric struct alignas(STACK_ALIGNMENT) ThreadAttributes {
82*bb722a7dSDimitry Andric   // We want the "detach_state" attribute to be an atomic value as it could be
83*bb722a7dSDimitry Andric   // updated by one thread while the self thread is reading it. It is a tristate
84*bb722a7dSDimitry Andric   // variable with the following state transitions:
85*bb722a7dSDimitry Andric   // 1. The a thread is created in a detached state, then user code should never
86*bb722a7dSDimitry Andric   //    call a detach or join function. Calling either of them can lead to
87*bb722a7dSDimitry Andric   //    undefined behavior.
88*bb722a7dSDimitry Andric   //    The value of |detach_state| is expected to be DetachState::DETACHED for
89*bb722a7dSDimitry Andric   //    its lifetime.
90*bb722a7dSDimitry Andric   // 2. If a thread is created in a joinable state, |detach_state| will start
91*bb722a7dSDimitry Andric   //    with the value DetachState::JOINABLE. Another thread can detach this
92*bb722a7dSDimitry Andric   //    thread before it exits. The state transitions will as follows:
93*bb722a7dSDimitry Andric   //      (a) If the detach method sees the state as JOINABLE, then it will
94*bb722a7dSDimitry Andric   //          compare exchange to a state of DETACHED. The thread will clean
95*bb722a7dSDimitry Andric   //          itself up after it finishes.
96*bb722a7dSDimitry Andric   //      (b) If the detach method does not see JOINABLE in (a), then it will
97*bb722a7dSDimitry Andric   //          conclude that the thread is EXITING and will wait until the thread
98*bb722a7dSDimitry Andric   //          exits. It will clean up the thread resources once the thread
99*bb722a7dSDimitry Andric   //          exits.
100*bb722a7dSDimitry Andric   cpp::Atomic<uint32_t> detach_state;
101*bb722a7dSDimitry Andric   void *stack;               // Pointer to the thread stack
102*bb722a7dSDimitry Andric   size_t stacksize;          // Size of the stack
103*bb722a7dSDimitry Andric   size_t guardsize;          // Guard size on stack
104*bb722a7dSDimitry Andric   uintptr_t tls;             // Address to the thread TLS memory
105*bb722a7dSDimitry Andric   uintptr_t tls_size;        // The size of area pointed to by |tls|.
106*bb722a7dSDimitry Andric   unsigned char owned_stack; // Indicates if the thread owns this stack memory
107*bb722a7dSDimitry Andric   int tid;
108*bb722a7dSDimitry Andric   ThreadStyle style;
109*bb722a7dSDimitry Andric   ThreadReturnValue retval;
110*bb722a7dSDimitry Andric   ThreadAtExitCallbackMgr *atexit_callback_mgr;
111*bb722a7dSDimitry Andric   void *platform_data;
112*bb722a7dSDimitry Andric 
ThreadAttributesThreadAttributes113*bb722a7dSDimitry Andric   constexpr ThreadAttributes()
114*bb722a7dSDimitry Andric       : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr),
115*bb722a7dSDimitry Andric         stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false),
116*bb722a7dSDimitry Andric         tid(-1), style(ThreadStyle::POSIX), retval(),
117*bb722a7dSDimitry Andric         atexit_callback_mgr(nullptr), platform_data(nullptr) {}
118*bb722a7dSDimitry Andric };
119*bb722a7dSDimitry Andric 
120*bb722a7dSDimitry Andric using TSSDtor = void(void *);
121*bb722a7dSDimitry Andric 
122*bb722a7dSDimitry Andric // Create a new TSS key and associate the |dtor| as the corresponding
123*bb722a7dSDimitry Andric // destructor. Can be used to implement public functions like
124*bb722a7dSDimitry Andric // pthread_key_create.
125*bb722a7dSDimitry Andric cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor);
126*bb722a7dSDimitry Andric 
127*bb722a7dSDimitry Andric // Delete the |key|. Can be used to implement public functions like
128*bb722a7dSDimitry Andric // pthread_key_delete.
129*bb722a7dSDimitry Andric //
130*bb722a7dSDimitry Andric // Return true on success, false on failure.
131*bb722a7dSDimitry Andric bool tss_key_delete(unsigned int key);
132*bb722a7dSDimitry Andric 
133*bb722a7dSDimitry Andric // Set the value associated with |key| for the current thread. Can be used
134*bb722a7dSDimitry Andric // to implement public functions like pthread_setspecific.
135*bb722a7dSDimitry Andric //
136*bb722a7dSDimitry Andric // Return true on success, false on failure.
137*bb722a7dSDimitry Andric bool set_tss_value(unsigned int key, void *value);
138*bb722a7dSDimitry Andric 
139*bb722a7dSDimitry Andric // Return the value associated with |key| for the current thread. Return
140*bb722a7dSDimitry Andric // nullptr if |key| is invalid. Can be used to implement public functions like
141*bb722a7dSDimitry Andric // pthread_getspecific.
142*bb722a7dSDimitry Andric void *get_tss_value(unsigned int key);
143*bb722a7dSDimitry Andric 
144*bb722a7dSDimitry Andric struct Thread {
145*bb722a7dSDimitry Andric   // NB: Default stacksize of 64kb is exceedingly small compared to the 2mb norm
146*bb722a7dSDimitry Andric   // and will break many programs expecting the full 2mb.
147*bb722a7dSDimitry Andric   static constexpr size_t DEFAULT_STACKSIZE = 1 << 16;
148*bb722a7dSDimitry Andric   static constexpr size_t DEFAULT_GUARDSIZE = EXEC_PAGESIZE;
149*bb722a7dSDimitry Andric   static constexpr bool DEFAULT_DETACHED = false;
150*bb722a7dSDimitry Andric 
151*bb722a7dSDimitry Andric   ThreadAttributes *attrib;
152*bb722a7dSDimitry Andric 
ThreadThread153*bb722a7dSDimitry Andric   constexpr Thread() : attrib(nullptr) {}
ThreadThread154*bb722a7dSDimitry Andric   constexpr Thread(ThreadAttributes *attr) : attrib(attr) {}
155*bb722a7dSDimitry Andric 
156*bb722a7dSDimitry Andric   int run(ThreadRunnerPosix *func, void *arg, void *stack = nullptr,
157*bb722a7dSDimitry Andric           size_t stacksize = DEFAULT_STACKSIZE,
158*bb722a7dSDimitry Andric           size_t guardsize = DEFAULT_GUARDSIZE,
159*bb722a7dSDimitry Andric           bool detached = DEFAULT_DETACHED) {
160*bb722a7dSDimitry Andric     ThreadRunner runner;
161*bb722a7dSDimitry Andric     runner.posix_runner = func;
162*bb722a7dSDimitry Andric     return run(ThreadStyle::POSIX, runner, arg, stack, stacksize, guardsize,
163*bb722a7dSDimitry Andric                detached);
164*bb722a7dSDimitry Andric   }
165*bb722a7dSDimitry Andric 
166*bb722a7dSDimitry Andric   int run(ThreadRunnerStdc *func, void *arg, void *stack = nullptr,
167*bb722a7dSDimitry Andric           size_t stacksize = DEFAULT_STACKSIZE,
168*bb722a7dSDimitry Andric           size_t guardsize = DEFAULT_GUARDSIZE,
169*bb722a7dSDimitry Andric           bool detached = DEFAULT_DETACHED) {
170*bb722a7dSDimitry Andric     ThreadRunner runner;
171*bb722a7dSDimitry Andric     runner.stdc_runner = func;
172*bb722a7dSDimitry Andric     return run(ThreadStyle::STDC, runner, arg, stack, stacksize, guardsize,
173*bb722a7dSDimitry Andric                detached);
174*bb722a7dSDimitry Andric   }
175*bb722a7dSDimitry Andric 
joinThread176*bb722a7dSDimitry Andric   int join(int *val) {
177*bb722a7dSDimitry Andric     ThreadReturnValue retval;
178*bb722a7dSDimitry Andric     int status = join(retval);
179*bb722a7dSDimitry Andric     if (status != 0)
180*bb722a7dSDimitry Andric       return status;
181*bb722a7dSDimitry Andric     if (val != nullptr)
182*bb722a7dSDimitry Andric       *val = retval.stdc_retval;
183*bb722a7dSDimitry Andric     return 0;
184*bb722a7dSDimitry Andric   }
185*bb722a7dSDimitry Andric 
joinThread186*bb722a7dSDimitry Andric   int join(void **val) {
187*bb722a7dSDimitry Andric     ThreadReturnValue retval;
188*bb722a7dSDimitry Andric     int status = join(retval);
189*bb722a7dSDimitry Andric     if (status != 0)
190*bb722a7dSDimitry Andric       return status;
191*bb722a7dSDimitry Andric     if (val != nullptr)
192*bb722a7dSDimitry Andric       *val = retval.posix_retval;
193*bb722a7dSDimitry Andric     return 0;
194*bb722a7dSDimitry Andric   }
195*bb722a7dSDimitry Andric 
196*bb722a7dSDimitry Andric   // Platform should implement the functions below.
197*bb722a7dSDimitry Andric 
198*bb722a7dSDimitry Andric   // Return 0 on success or an error value on failure.
199*bb722a7dSDimitry Andric   int run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
200*bb722a7dSDimitry Andric           size_t stacksize, size_t guardsize, bool detached);
201*bb722a7dSDimitry Andric 
202*bb722a7dSDimitry Andric   // Return 0 on success or an error value on failure.
203*bb722a7dSDimitry Andric   int join(ThreadReturnValue &retval);
204*bb722a7dSDimitry Andric 
205*bb722a7dSDimitry Andric   // Detach a joinable thread.
206*bb722a7dSDimitry Andric   //
207*bb722a7dSDimitry Andric   // This method does not have error return value. However, the type of detach
208*bb722a7dSDimitry Andric   // is returned to help with testing.
209*bb722a7dSDimitry Andric   int detach();
210*bb722a7dSDimitry Andric 
211*bb722a7dSDimitry Andric   // Wait for the thread to finish. This method can only be called
212*bb722a7dSDimitry Andric   // if:
213*bb722a7dSDimitry Andric   // 1. A detached thread is guaranteed to be running.
214*bb722a7dSDimitry Andric   // 2. A joinable thread has not been detached or joined. As long as it has
215*bb722a7dSDimitry Andric   //    not been detached or joined, wait can be called multiple times.
216*bb722a7dSDimitry Andric   //
217*bb722a7dSDimitry Andric   // Also, only one thread can wait and expect to get woken up when the thread
218*bb722a7dSDimitry Andric   // finishes.
219*bb722a7dSDimitry Andric   //
220*bb722a7dSDimitry Andric   // NOTE: This function is to be used for testing only. There is no standard
221*bb722a7dSDimitry Andric   // which requires exposing it via a public API.
222*bb722a7dSDimitry Andric   void wait();
223*bb722a7dSDimitry Andric 
224*bb722a7dSDimitry Andric   // Return true if this thread is equal to the other thread.
225*bb722a7dSDimitry Andric   bool operator==(const Thread &other) const;
226*bb722a7dSDimitry Andric 
227*bb722a7dSDimitry Andric   // Set the name of the thread. Return the error number on error.
228*bb722a7dSDimitry Andric   int set_name(const cpp::string_view &name);
229*bb722a7dSDimitry Andric 
230*bb722a7dSDimitry Andric   // Return the name of the thread in |name|. Return the error number of error.
231*bb722a7dSDimitry Andric   int get_name(cpp::StringStream &name) const;
232*bb722a7dSDimitry Andric };
233*bb722a7dSDimitry Andric 
234*bb722a7dSDimitry Andric LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;
235*bb722a7dSDimitry Andric 
236*bb722a7dSDimitry Andric // Platforms should implement this function.
237*bb722a7dSDimitry Andric [[noreturn]] void thread_exit(ThreadReturnValue retval, ThreadStyle style);
238*bb722a7dSDimitry Andric 
239*bb722a7dSDimitry Andric namespace internal {
240*bb722a7dSDimitry Andric // Internal namespace containing utilities which are to be used by platform
241*bb722a7dSDimitry Andric // implementations of threads.
242*bb722a7dSDimitry Andric 
243*bb722a7dSDimitry Andric // Return the current thread's atexit callback manager. After thread startup
244*bb722a7dSDimitry Andric // but before running the thread function, platform implementations should
245*bb722a7dSDimitry Andric // set the "atexit_callback_mgr" field of the thread's attributes to the value
246*bb722a7dSDimitry Andric // returned by this function.
247*bb722a7dSDimitry Andric ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr();
248*bb722a7dSDimitry Andric 
249*bb722a7dSDimitry Andric // Call the currently registered thread specific atexit callbacks. Useful for
250*bb722a7dSDimitry Andric // implementing the thread_exit function.
251*bb722a7dSDimitry Andric void call_atexit_callbacks(ThreadAttributes *attrib);
252*bb722a7dSDimitry Andric 
253*bb722a7dSDimitry Andric } // namespace internal
254*bb722a7dSDimitry Andric 
255*bb722a7dSDimitry Andric } // namespace LIBC_NAMESPACE_DECL
256*bb722a7dSDimitry Andric 
257*bb722a7dSDimitry Andric #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
258