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