1 //===--- Definitions of common thread items ---------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "src/__support/threads/thread.h"
10 #include "src/__support/macros/config.h"
11 #include "src/__support/threads/mutex.h"
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"
19 namespace LIBC_NAMESPACE_DECL
{
22 using AtExitCallback
= void(void *);
25 AtExitCallback
*callback
= nullptr;
27 constexpr AtExitUnit() = default;
28 constexpr AtExitUnit(AtExitCallback
*cb
, void *o
) : callback(cb
), obj(o
) {}
31 constexpr size_t TSS_KEY_COUNT
= 1024;
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.
39 TSSDtor
*dtor
= nullptr;
41 constexpr TSSKeyUnit() = default;
42 constexpr TSSKeyUnit(TSSDtor
*d
) : active(true), dtor(d
) {}
52 cpp::array
<TSSKeyUnit
, TSS_KEY_COUNT
> units
;
56 : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
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
];
68 return cpp::optional
<unsigned int>();
71 TSSDtor
*get_dtor(unsigned int key
) {
72 if (key
>= TSS_KEY_COUNT
)
74 cpp::lock_guard
lock(mtx
);
75 return units
[key
].dtor
;
78 bool remove_key(unsigned int key
) {
79 if (key
>= TSS_KEY_COUNT
)
81 cpp::lock_guard
lock(mtx
);
86 bool is_valid_key(unsigned int key
) {
87 cpp::lock_guard
lock(mtx
);
88 return units
[key
].active
;
92 TSSKeyMgr tss_key_mgr
;
96 void *payload
= nullptr;
97 TSSDtor
*dtor
= nullptr;
99 constexpr TSSValueUnit() = default;
100 constexpr TSSValueUnit(void *p
, TSSDtor
*d
)
101 : active(true), payload(p
), dtor(d
) {}
104 static LIBC_THREAD_LOCAL
cpp::array
<TSSValueUnit
, TSS_KEY_COUNT
> tss_values
;
106 } // anonymous namespace
108 class ThreadAtExitCallbackMgr
{
110 // TODO: Use a BlockStore when compiled for production.
111 FixedVector
<AtExitUnit
, 1024> callback_list
;
114 constexpr ThreadAtExitCallbackMgr()
115 : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
116 /*pshared=*/false) {}
118 int add_callback(AtExitCallback
*callback
, void *obj
) {
119 cpp::lock_guard
lock(mtx
);
120 return callback_list
.push_back({callback
, obj
});
125 while (!callback_list
.empty()) {
126 auto atexit_unit
= callback_list
.back();
127 callback_list
.pop_back();
129 atexit_unit
.callback(atexit_unit
.obj
);
135 static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr
;
137 // The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi.
138 // It is used by thread local object runtime to register destructor calls. To
139 // actually register destructor call with the threading library, it calls
140 // __cxa_thread_atexit_impl, which is to be provided by the threading library.
141 // The semantics are very similar to the __cxa_atexit function except for the
142 // fact that the registered callback is thread specific.
143 extern "C" int __cxa_thread_atexit_impl(AtExitCallback
*callback
, void *obj
,
145 return atexit_callback_mgr
.add_callback(callback
, obj
);
150 ThreadAtExitCallbackMgr
*get_thread_atexit_callback_mgr() {
151 return &atexit_callback_mgr
;
154 void call_atexit_callbacks(ThreadAttributes
*attrib
) {
155 attrib
->atexit_callback_mgr
->call();
156 for (size_t i
= 0; i
< TSS_KEY_COUNT
; ++i
) {
157 TSSValueUnit
&unit
= tss_values
[i
];
158 // Both dtor and value need to nonnull to call dtor
159 if (unit
.dtor
!= nullptr && unit
.payload
!= nullptr)
160 unit
.dtor(unit
.payload
);
164 } // namespace internal
166 cpp::optional
<unsigned int> new_tss_key(TSSDtor
*dtor
) {
167 return tss_key_mgr
.new_key(dtor
);
170 bool tss_key_delete(unsigned int key
) { return tss_key_mgr
.remove_key(key
); }
172 bool set_tss_value(unsigned int key
, void *val
) {
173 if (!tss_key_mgr
.is_valid_key(key
))
175 tss_values
[key
] = {val
, tss_key_mgr
.get_dtor(key
)};
179 void *get_tss_value(unsigned int key
) {
180 if (key
>= TSS_KEY_COUNT
)
183 auto &u
= tss_values
[key
];
189 } // namespace LIBC_NAMESPACE_DECL