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