Skip to content

Commit 175ae9a

Browse files
[libc] ensure tls dtors are called in main thread
1 parent eba3734 commit 175ae9a

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-2
lines changed

libc/src/__support/threads/thread.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() {
154154
}
155155

156156
void call_atexit_callbacks(ThreadAttributes *attrib) {
157+
if (attrib->dtors_called)
158+
return;
159+
attrib->dtors_called = true;
157160
attrib->atexit_callback_mgr->call();
158161
for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {
159162
TSSValueUnit &unit = tss_values[i];
@@ -163,6 +166,8 @@ void call_atexit_callbacks(ThreadAttributes *attrib) {
163166
}
164167
}
165168

169+
extern "C" void __cxa_thread_finalize() { call_atexit_callbacks(self.attrib); }
170+
166171
} // namespace internal
167172

168173
cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) {

libc/src/__support/threads/thread.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes {
109109
ThreadReturnValue retval;
110110
ThreadAtExitCallbackMgr *atexit_callback_mgr;
111111
void *platform_data;
112+
bool dtors_called;
112113

113-
constexpr ThreadAttributes()
114+
LIBC_INLINE constexpr ThreadAttributes()
114115
: detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr),
115116
stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false),
116117
tid(-1), style(ThreadStyle::POSIX), retval(),
117-
atexit_callback_mgr(nullptr), platform_data(nullptr) {}
118+
atexit_callback_mgr(nullptr), platform_data(nullptr),
119+
dtors_called(false) {}
118120
};
119121

120122
using TSSDtor = void(void *);

libc/src/stdlib/exit.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
namespace LIBC_NAMESPACE_DECL {
1515

1616
extern "C" void __cxa_finalize(void *);
17+
extern "C" [[gnu::weak]] void __cxa_thread_finalize();
1718

19+
// TODO: use recursive mutex to protect this routine.
1820
[[noreturn]] LLVM_LIBC_FUNCTION(void, exit, (int status)) {
21+
if (__cxa_thread_finalize)
22+
__cxa_thread_finalize();
1923
__cxa_finalize(nullptr);
2024
internal::exit(status);
2125
}

libc/test/integration/src/__support/threads/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,24 @@ add_integration_test(
2525
DEPENDS
2626
libc.src.__support.threads.thread
2727
)
28+
29+
add_integration_test(
30+
main_exit_test
31+
SUITE
32+
libc-support-threads-integration-tests
33+
SRCS
34+
main_exit_test.cpp
35+
DEPENDS
36+
libc.src.__support.threads.thread
37+
)
38+
39+
add_integration_test(
40+
double_exit_test
41+
SUITE
42+
libc-support-threads-integration-tests
43+
SRCS
44+
double_exit_test.cpp
45+
DEPENDS
46+
libc.src.__support.threads.thread
47+
libc.src.stdlib.exit
48+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Test handling of thread local data --------------------------------===//
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/stdlib/exit.h"
11+
#include "test/IntegrationTest/test.h"
12+
13+
extern "C" {
14+
[[gnu::weak]]
15+
void *__dso_handle = nullptr;
16+
int __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso);
17+
}
18+
19+
TEST_MAIN() {
20+
__cxa_thread_atexit_impl([](void *) { LIBC_NAMESPACE::exit(0); }, nullptr,
21+
__dso_handle);
22+
return 0;
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===-- Test handling of thread local data --------------------------------===//
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 "test/IntegrationTest/test.h"
11+
12+
bool called = false;
13+
14+
extern "C" {
15+
[[gnu::weak]]
16+
void *__dso_handle = nullptr;
17+
int __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso);
18+
}
19+
20+
[[gnu::destructor]]
21+
void destructor() {
22+
if (!called)
23+
__builtin_trap();
24+
}
25+
26+
TEST_MAIN() {
27+
__cxa_thread_atexit_impl([](void *) { called = true; }, nullptr,
28+
__dso_handle);
29+
return 0;
30+
}

0 commit comments

Comments
 (0)