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 //===----------------------------------------------------------------------===//
12 #include "src/__support/CPP/array.h"
13 #include "src/__support/CPP/optional.h"
14 #include "src/__support/fixedvector.h"
16 namespace __llvm_libc
{
18 thread_local Thread self
;
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
;
55 constexpr TSSKeyMgr() : mtx(false, false, false) {}
57 cpp::optional
<unsigned int> new_key(TSSDtor
*dtor
) {
59 for (size_t i
= 0; i
< TSS_KEY_COUNT
; ++i
) {
60 TSSKeyUnit
&u
= units
[i
];
66 return cpp::optional
<unsigned int>();
69 TSSDtor
*get_dtor(unsigned int key
) {
70 if (key
>= TSS_KEY_COUNT
)
73 return units
[key
].dtor
;
76 bool remove_key(unsigned int key
) {
77 if (key
>= TSS_KEY_COUNT
)
84 bool is_valid_key(unsigned int key
) {
86 return units
[key
].active
;
90 TSSKeyMgr tss_key_mgr
;
94 void *payload
= nullptr;
95 TSSDtor
*dtor
= nullptr;
97 constexpr TSSValueUnit() = default;
98 constexpr TSSValueUnit(void *p
, TSSDtor
*d
)
99 : active(true), payload(p
), dtor(d
) {}
102 static thread_local
cpp::array
<TSSValueUnit
, TSS_KEY_COUNT
> tss_values
;
104 } // anonymous namespace
106 class ThreadAtExitCallbackMgr
{
108 // TODO: Use a BlockStore when compiled for production.
109 FixedVector
<AtExitUnit
, 1024> callback_list
;
112 constexpr ThreadAtExitCallbackMgr() : mtx(false, false, false) {}
114 int add_callback(AtExitCallback
*callback
, void *obj
) {
115 MutexLock
lock(&mtx
);
116 return callback_list
.push_back({callback
, obj
});
121 while (!callback_list
.empty()) {
122 auto atexit_unit
= callback_list
.back();
123 callback_list
.pop_back();
125 atexit_unit
.callback(atexit_unit
.obj
);
131 static thread_local ThreadAtExitCallbackMgr atexit_callback_mgr
;
133 // The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi.
134 // It is used by thread local object runtime to register destructor calls. To
135 // actually register destructor call with the threading library, it calls
136 // __cxa_thread_atexit_impl, which is to be provided by the threading library.
137 // The semantics are very similar to the __cxa_atexit function except for the
138 // fact that the registered callback is thread specific.
139 extern "C" int __cxa_thread_atexit_impl(AtExitCallback
*callback
, void *obj
,
141 return atexit_callback_mgr
.add_callback(callback
, obj
);
146 ThreadAtExitCallbackMgr
*get_thread_atexit_callback_mgr() {
147 return &atexit_callback_mgr
;
150 void call_atexit_callbacks(ThreadAttributes
*attrib
) {
151 attrib
->atexit_callback_mgr
->call();
152 for (size_t i
= 0; i
< TSS_KEY_COUNT
; ++i
) {
153 TSSValueUnit
&unit
= tss_values
[i
];
154 // Both dtor and value need to nonnull to call dtor
155 if (unit
.dtor
!= nullptr && unit
.payload
!= nullptr)
156 unit
.dtor(unit
.payload
);
160 } // namespace internal
162 cpp::optional
<unsigned int> new_tss_key(TSSDtor
*dtor
) {
163 return tss_key_mgr
.new_key(dtor
);
166 bool tss_key_delete(unsigned int key
) { return tss_key_mgr
.remove_key(key
); }
168 bool set_tss_value(unsigned int key
, void *val
) {
169 if (!tss_key_mgr
.is_valid_key(key
))
171 tss_values
[key
] = {val
, tss_key_mgr
.get_dtor(key
)};
175 void *get_tss_value(unsigned int key
) {
176 if (key
>= TSS_KEY_COUNT
)
179 auto &u
= tss_values
[key
];
185 } // namespace __llvm_libc