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