blob: 748b0eb11962299af2f785dd81b73f7327917ac3 [file] [log] [blame]
Dan Albertefa37d12014-12-18 00:03:57 +00001//===----------------------- 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
Eric Fiselier3f7b3702016-10-12 08:54:10 +000010#include "abort_message.h"
Dan Albertefa37d12014-12-18 00:03:57 +000011#include "cxxabi.h"
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000012#include <__threading_support>
Eric Fiselier3f7b3702016-10-12 08:54:10 +000013#include <cstdlib>
Dan Albertefa37d12014-12-18 00:03:57 +000014
15namespace __cxxabiv1 {
Dan Albertefa37d12014-12-18 00:03:57 +000016
Eric Fiselier3f7b3702016-10-12 08:54:10 +000017 using Dtor = void(*)(void*);
Dan Albertefa37d12014-12-18 00:03:57 +000018
Eric Fiselier3f7b3702016-10-12 08:54:10 +000019 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 __attribute__((__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
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000042 // through the __libccpp_tls_key destructors.
Asiri Rathnayake51806732016-10-13 15:05:19 +000043 // 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.
Eric Fiselier3f7b3702016-10-12 08:54:10 +000046 //
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
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000069 std::__libcpp_tls_key dtors_key;
Eric Fiselier3f7b3702016-10-12 08:54:10 +000070
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() {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000083 // There is intentionally no matching std::__libcpp_tls_delete call, as
Eric Fiselier3f7b3702016-10-12 08:54:10 +000084 // __cxa_thread_atexit() may be called arbitrarily late (for example, from
85 // global destructors or atexit() handlers).
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000086 if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
87 abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
Eric Fiselier3f7b3702016-10-12 08:54:10 +000088 }
89 }
90
91 ~DtorsManager() {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000092 // std::__libcpp_tls_key destructors do not run on threads that call exit()
Eric Fiselier3f7b3702016-10-12 08:54:10 +000093 // (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
Dan Albertefa37d12014-12-18 00:03:57 +0000101
Vitaly Bukae4b123b2016-10-15 00:02:20 +0000102#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
Dan Albertefa37d12014-12-18 00:03:57 +0000103
Eric Fiselier3f7b3702016-10-12 08:54:10 +0000104extern "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 {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000113 // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
Asiri Rathnayake51806732016-10-13 15:05:19 +0000114 // one-time initialization and __cxa_atexit() for destruction)
Eric Fiselier3f7b3702016-10-12 08:54:10 +0000115 static DtorsManager manager;
116
117 if (!dtors_alive) {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000118 if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
Eric Fiselier3f7b3702016-10-12 08:54:10 +0000119 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
Dan Albertefa37d12014-12-18 00:03:57 +0000139} // extern "C"
Dan Albertefa37d12014-12-18 00:03:57 +0000140} // namespace __cxxabiv1