Ticket #52585: cxa_thread_atexit.cpp

File cxa_thread_atexit.cpp, 4.6 KB (added by ken-cunningham-webuse, 8 years ago)

replacement file for src/cxa_thread_atexit.cpp

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