1//===----------------------------------------------------------------------===//
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 "cxxabi.h"
10
11#if !defined(_LIBCXXABI_HAS_NO_THREADS) && _LIBCXXABI_DEFINE_THREAD_ATEXIT
12
13#include <__thread/support.h>
14#include <stdlib.h>
15
16#include "abort_message.h"
17
18#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
19#pragma comment(lib, "pthread")
20#endif
21
22namespace __cxxabiv1 {
23
24 using Dtor = void(*)(void*);
25
26 extern "C"
27#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
28 // A weak symbol is used to detect this function's presence in the C library
29 // at runtime, even if libc++ is built against an older libc
30 _LIBCXXABI_WEAK
31#endif
32 int __cxa_thread_atexit_impl(Dtor, void*, void*);
33
34#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
35
36namespace {
37 // This implementation is used if the C library does not provide
38 // __cxa_thread_atexit_impl() for us. It has a number of limitations that are
39 // difficult to impossible to address without ..._impl():
40 //
41 // - dso_symbol is ignored. This means that a shared library may be unloaded
42 // (via dlclose()) before its thread_local destructors have run.
43 //
44 // - thread_local destructors for the main thread are run by the destructor of
45 // a static object. This is later than expected; they should run before the
46 // destructors of any objects with static storage duration.
47 //
48 // - thread_local destructors on non-main threads run on the first iteration
49 // through the __libccpp_tls_key destructors.
50 // std::notify_all_at_thread_exit() and similar functions must be careful to
51 // wait until the second iteration to provide their intended ordering
52 // guarantees.
53 //
54 // Another limitation, though one shared with ..._impl(), is that any
55 // thread_locals that are first initialized after non-thread_local global
56 // destructors begin to run will not be destroyed. [basic.start.term] states
57 // that all thread_local destructors are sequenced before the destruction of
58 // objects with static storage duration, resulting in a contradiction if a
59 // thread_local is constructed after that point. Thus we consider such
60 // programs ill-formed, and don't bother to run those destructors. (If the
61 // program terminates abnormally after such a thread_local is constructed,
62 // the destructor is not expected to run and thus there is no contradiction.
63 // So construction still has to work.)
64
65 struct DtorList {
66 Dtor dtor;
67 void* obj;
68 DtorList* next;
69 };
70
71 // The linked list of thread-local destructors to run
72 __thread DtorList* dtors = nullptr;
73 // True if the destructors are currently scheduled to run on this thread
74 __thread bool dtors_alive = false;
75 // Used to trigger destructors on thread exit; value is ignored
76 std::__libcpp_tls_key dtors_key;
77
78 // The calling convention of TLS destructors is dictated by the underlying
79 // threading API.
80 void _LIBCPP_TLS_DESTRUCTOR_CC run_dtors(void*) {
81 while (auto head = dtors) {
82 dtors = head->next;
83 head->dtor(head->obj);
84 ::free(head);
85 }
86
87 dtors_alive = false;
88 }
89
90 struct DtorsManager {
91 DtorsManager() {
92 // There is intentionally no matching std::__libcpp_tls_delete call, as
93 // __cxa_thread_atexit() may be called arbitrarily late (for example, from
94 // global destructors or atexit() handlers).
95 if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
96 __abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
97 }
98 }
99
100 ~DtorsManager() {
101 // std::__libcpp_tls_key destructors do not run on threads that call exit()
102 // (including when the main thread returns from main()), so we explicitly
103 // call the destructor here. This runs at exit time (potentially earlier
104 // if libc++abi is dlclose()'d). Any thread_locals initialized after this
105 // point will not be destroyed.
106 run_dtors(nullptr);
107 }
108 };
109} // namespace
110
111#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
112
113extern "C" {
114
115 _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
116#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
117 return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
118#else
119 if (__cxa_thread_atexit_impl) {
120 return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
121 } else {
122 // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
123 // one-time initialization and __cxa_atexit() for destruction)
124 static DtorsManager manager;
125
126 if (!dtors_alive) {
127 if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
128 return -1;
129 }
130 dtors_alive = true;
131 }
132
133 auto head = static_cast<DtorList*>(::malloc(sizeof(DtorList)));
134 if (!head) {
135 return -1;
136 }
137
138 head->dtor = dtor;
139 head->obj = obj;
140 head->next = dtors;
141 dtors = head;
142
143 return 0;
144 }
145#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
146 }
147
148} // extern "C"
149
150} // namespace __cxxabiv1
151
152#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && _LIBCXXABI_DEFINE_THREAD_ATEXIT
153