1 | //===--- Definitions of common thread items ---------------------*- 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 | #include "src/__support/threads/thread.h" |
10 | #include "src/__support/macros/config.h" |
11 | #include "src/__support/threads/mutex.h" |
12 | |
13 | #include "src/__support/CPP/array.h" |
14 | #include "src/__support/CPP/mutex.h" // lock_guard |
15 | #include "src/__support/CPP/optional.h" |
16 | #include "src/__support/fixedvector.h" |
17 | #include "src/__support/macros/attributes.h" |
18 | |
19 | namespace LIBC_NAMESPACE_DECL { |
20 | namespace { |
21 | |
22 | using AtExitCallback = void(void *); |
23 | |
24 | struct AtExitUnit { |
25 | AtExitCallback *callback = nullptr; |
26 | void *obj = nullptr; |
27 | constexpr AtExitUnit() = default; |
28 | constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {} |
29 | }; |
30 | |
31 | constexpr size_t TSS_KEY_COUNT = 1024; |
32 | |
33 | struct TSSKeyUnit { |
34 | // Indicates whether is unit is active. Presence of a non-null dtor |
35 | // is not sufficient to indicate the same information as a TSS key can |
36 | // have a null destructor. |
37 | bool active = false; |
38 | |
39 | TSSDtor *dtor = nullptr; |
40 | |
41 | constexpr TSSKeyUnit() = default; |
42 | constexpr TSSKeyUnit(TSSDtor *d) : active(true), dtor(d) {} |
43 | |
44 | void reset() { |
45 | active = false; |
46 | dtor = nullptr; |
47 | } |
48 | }; |
49 | |
50 | class TSSKeyMgr { |
51 | Mutex mtx; |
52 | cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units; |
53 | |
54 | public: |
55 | constexpr TSSKeyMgr() |
56 | : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false, |
57 | /*pshared=*/false) {} |
58 | |
59 | cpp::optional<unsigned int> new_key(TSSDtor *dtor) { |
60 | cpp::lock_guard lock(mtx); |
61 | for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) { |
62 | TSSKeyUnit &u = units[i]; |
63 | if (!u.active) { |
64 | u = {dtor}; |
65 | return i; |
66 | } |
67 | } |
68 | return cpp::optional<unsigned int>(); |
69 | } |
70 | |
71 | TSSDtor *get_dtor(unsigned int key) { |
72 | if (key >= TSS_KEY_COUNT) |
73 | return nullptr; |
74 | cpp::lock_guard lock(mtx); |
75 | return units[key].dtor; |
76 | } |
77 | |
78 | bool remove_key(unsigned int key) { |
79 | if (key >= TSS_KEY_COUNT) |
80 | return false; |
81 | cpp::lock_guard lock(mtx); |
82 | units[key].reset(); |
83 | return true; |
84 | } |
85 | |
86 | bool is_valid_key(unsigned int key) { |
87 | cpp::lock_guard lock(mtx); |
88 | return units[key].active; |
89 | } |
90 | }; |
91 | |
92 | TSSKeyMgr tss_key_mgr; |
93 | |
94 | struct TSSValueUnit { |
95 | bool active = false; |
96 | void *payload = nullptr; |
97 | TSSDtor *dtor = nullptr; |
98 | |
99 | constexpr TSSValueUnit() = default; |
100 | constexpr TSSValueUnit(void *p, TSSDtor *d) |
101 | : active(true), payload(p), dtor(d) {} |
102 | }; |
103 | |
104 | static LIBC_THREAD_LOCAL cpp::array<TSSValueUnit, TSS_KEY_COUNT> tss_values; |
105 | |
106 | } // anonymous namespace |
107 | |
108 | class ThreadAtExitCallbackMgr { |
109 | Mutex mtx; |
110 | // TODO: Use a BlockStore when compiled for production. |
111 | FixedVector<AtExitUnit, 1024> callback_list; |
112 | |
113 | public: |
114 | constexpr ThreadAtExitCallbackMgr() |
115 | : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false, |
116 | /*pshared=*/false) {} |
117 | |
118 | int add_callback(AtExitCallback *callback, void *obj) { |
119 | cpp::lock_guard lock(mtx); |
120 | if (callback_list.push_back({callback, obj})) |
121 | return 0; |
122 | return -1; |
123 | } |
124 | |
125 | void call() { |
126 | mtx.lock(); |
127 | while (!callback_list.empty()) { |
128 | auto atexit_unit = callback_list.back(); |
129 | callback_list.pop_back(); |
130 | mtx.unlock(); |
131 | atexit_unit.callback(atexit_unit.obj); |
132 | mtx.lock(); |
133 | } |
134 | } |
135 | }; |
136 | |
137 | static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr; |
138 | |
139 | // The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi. |
140 | // It is used by thread local object runtime to register destructor calls. To |
141 | // actually register destructor call with the threading library, it calls |
142 | // __cxa_thread_atexit_impl, which is to be provided by the threading library. |
143 | // The semantics are very similar to the __cxa_atexit function except for the |
144 | // fact that the registered callback is thread specific. |
145 | extern "C"int __cxa_thread_atexit_impl(AtExitCallback *callback, void *obj, |
146 | void *) { |
147 | return atexit_callback_mgr.add_callback(callback, obj); |
148 | } |
149 | |
150 | namespace internal { |
151 | |
152 | ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() { |
153 | return &atexit_callback_mgr; |
154 | } |
155 | |
156 | void call_atexit_callbacks(ThreadAttributes *attrib) { |
157 | attrib->atexit_callback_mgr->call(); |
158 | for (size_t i = 0; i < TSS_KEY_COUNT; ++i) { |
159 | TSSValueUnit &unit = tss_values[i]; |
160 | // Both dtor and value need to nonnull to call dtor |
161 | if (unit.dtor != nullptr && unit.payload != nullptr) |
162 | unit.dtor(unit.payload); |
163 | } |
164 | } |
165 | |
166 | } // namespace internal |
167 | |
168 | cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) { |
169 | return tss_key_mgr.new_key(dtor); |
170 | } |
171 | |
172 | bool tss_key_delete(unsigned int key) { return tss_key_mgr.remove_key(key); } |
173 | |
174 | bool set_tss_value(unsigned int key, void *val) { |
175 | if (!tss_key_mgr.is_valid_key(key)) |
176 | return false; |
177 | tss_values[key] = {val, tss_key_mgr.get_dtor(key)}; |
178 | return true; |
179 | } |
180 | |
181 | void *get_tss_value(unsigned int key) { |
182 | if (key >= TSS_KEY_COUNT) |
183 | return nullptr; |
184 | |
185 | auto &u = tss_values[key]; |
186 | if (!u.active) |
187 | return nullptr; |
188 | return u.payload; |
189 | } |
190 | |
191 | } // namespace LIBC_NAMESPACE_DECL |
192 |
Definitions
- AtExitUnit
- AtExitUnit
- AtExitUnit
- TSS_KEY_COUNT
- TSSKeyUnit
- TSSKeyUnit
- TSSKeyUnit
- reset
- TSSKeyMgr
- TSSKeyMgr
- new_key
- get_dtor
- remove_key
- is_valid_key
- tss_key_mgr
- TSSValueUnit
- TSSValueUnit
- TSSValueUnit
- ThreadAtExitCallbackMgr
- ThreadAtExitCallbackMgr
- add_callback
- call
- ThreadAtExitCallbackMgr
- __cxa_thread_atexit_impl
- get_thread_atexit_callback_mgr
- call_atexit_callbacks
- new_tss_key
- tss_key_delete
- set_tss_value
Improve your Profiling and Debugging skills
Find out more