tavianator updated this revision to Diff 62388.
tavianator added a comment.

Added missing __dso_handle declaration.


http://reviews.llvm.org/D21803

Files:
  cmake/config-ix.cmake
  src/CMakeLists.txt
  src/cxa_thread_atexit.cpp
  test/CMakeLists.txt
  test/cxa_thread_atexit_test.pass.cpp
  test/libcxxabi/test/config.py
  test/lit.site.cfg.in

Index: test/lit.site.cfg.in
===================================================================
--- test/lit.site.cfg.in
+++ test/lit.site.cfg.in
@@ -13,7 +13,6 @@
 config.enable_32bit             = "@LIBCXXABI_BUILD_32_BITS@"
 config.target_info              = "@LIBCXXABI_TARGET_INFO@"
 config.executor                 = "@LIBCXXABI_EXECUTOR@"
-config.thread_atexit            = "@LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL@"
 config.libcxxabi_shared         = "@LIBCXXABI_ENABLE_SHARED@"
 config.enable_shared            = "@LIBCXX_ENABLE_SHARED@"
 config.enable_exceptions        = "@LIBCXXABI_ENABLE_EXCEPTIONS@"
Index: test/libcxxabi/test/config.py
===================================================================
--- test/libcxxabi/test/config.py
+++ test/libcxxabi/test/config.py
@@ -37,8 +37,6 @@
         super(Configuration, self).configure_features()
         if not self.get_lit_bool('enable_exceptions', True):
             self.config.available_features.add('libcxxabi-no-exceptions')
-        if self.get_lit_bool('thread_atexit', True):
-            self.config.available_features.add('thread_atexit')
 
     def configure_compile_flags(self):
         self.cxx.compile_flags += ['-DLIBCXXABI_NO_TIMER']
Index: test/cxa_thread_atexit_test.pass.cpp
===================================================================
--- test/cxa_thread_atexit_test.pass.cpp
+++ test/cxa_thread_atexit_test.pass.cpp
@@ -8,7 +8,6 @@
 //===----------------------------------------------------------------------===//
 
 // REQUIRES: linux
-// REQUIRES: thread_atexit
 
 #include <assert.h>
 #include <cxxabi.h>
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -16,7 +16,6 @@
 pythonize_bool(LIBCXXABI_ENABLE_THREADS)
 pythonize_bool(LIBCXXABI_ENABLE_EXCEPTIONS)
 pythonize_bool(LIBCXXABI_USE_LLVM_UNWINDER)
-pythonize_bool(LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL)
 set(LIBCXXABI_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
     "TargetInfo to use when setting up test environment.")
 set(LIBCXXABI_EXECUTOR "None" CACHE STRING
Index: src/cxa_thread_atexit.cpp
===================================================================
--- src/cxa_thread_atexit.cpp
+++ src/cxa_thread_atexit.cpp
@@ -7,20 +7,137 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "abort_message.h"
 #include "cxxabi.h"
+#include <cstdlib>
+#include <pthread.h>
 
 namespace __cxxabiv1 {
+namespace {
+  // This implementation is used if the C library does not provide
+  // __cxa_thread_atexit_impl() for us.  It has a number of limitations that are
+  // difficult to impossible to address without ..._impl():
+  //
+  // - dso_symbol is ignored.  This means that a shared library may be unloaded
+  //   (via dlclose()) before its thread_local destructors have run.
+  //
+  // - thread_local destructors for the main thread are run with __cxa_atexit().
+  //   This is later than expected; they should run before the destructors of
+  //   any objects with static storage duration.
+  //
+  // - thread_local destructors on other threads run on the first iteration
+  //   through the pthread_key destructors.  std::notify_all_at_thread_exit()
+  //   and similar functions must be careful to wait until the second iteration
+  //   to provide their indended ordering guarantees.
+
+  typedef void (*Dtor)(void*);
+
+  struct DtorList {
+    Dtor dtor;
+    void* obj;
+    DtorList* next;
+  };
+
+  pthread_key_t dtors;
+  pthread_once_t dtors_once = PTHREAD_ONCE_INIT;
+  bool dtors_ready = false;
+  bool dtors_atexit = false;
+
+  void run_dtors(void* ptr) {
+    if (pthread_setspecific(dtors, ptr) != 0) {
+      abort_message("pthread_setspecific() failed during thread_local destruction");
+    }
+
+    // Rather than iterate over the list directly, use the pthread_key to get
+    // the head of the list every time.  This gives the correct ordering if
+    // __cxa_thread_atexit() is called during the loop.
+    while (auto elem = static_cast<DtorList*>(pthread_getspecific(dtors))) {
+      if (pthread_setspecific(dtors, ptr) != 0) {
+        abort_message("pthread_setspecific() failed during thread_local destruction");
+      }
+      elem->dtor(elem->obj);
+      std::free(elem);
+    }
+  }
+
+  void run_dtors_atexit(void*) {
+    // Signify that we need to re-register this function if any new
+    // thread_locals are created.
+    dtors_atexit = false;
+
+    auto ptr = pthread_getspecific(dtors);
+    run_dtors(ptr);
+  }
+
+  // This is the DSO handle for libc++abi.so itself
+  extern "C" void* __dso_handle;
+
+  void dtors_init() {
+    // There is intentionally no matching pthread_key_delete call, as
+    // __cxa_thread_atexit() may be called arbitrarily late (for example, from
+    // global destructors or atexit() handlers).
+    if (pthread_key_create(&dtors, run_dtors) != 0) {
+      return;
+    }
+
+    // pthread_key destructors do not run on threads that call exit() (including
+    // when the main thread returns from main()).  Explicitly register an atexit
+    // handler to handle that case.
+    if (__cxa_atexit(run_dtors_atexit, NULL, __dso_handle) != 0) {
+      return;
+    }
+
+    dtors_ready = true;
+    dtors_atexit = true;
+  }
+} // namespace
+
 extern "C" {
 
-#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
+_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj,
+                                            void* dso_symbol) throw() {
+  // A weak symbol is used to detect this function's presence in the C library
+  extern int __cxa_thread_atexit_impl(Dtor, void *, void *)
+    __attribute__((__weak__));
+
+  if (__cxa_thread_atexit_impl) {
+    return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
+  } else {
+    if (pthread_once(&dtors_once, dtors_init) != 0) {
+      return -1;
+    }
+    if (!dtors_ready) {
+      return -1;
+    }
+
+    // It's possible for __cxa_thread_atexit() to be called after dtors_atexit()
+    // has already run, for example if a global destructor or atexit() handler
+    // reaches a thread_local for the first time.  Re-register the atexit()
+    // handler in that case.
+    if (!dtors_atexit) {
+      if (__cxa_atexit(run_dtors_atexit, NULL, __dso_handle) != 0) {
+        return -1;
+      }
+      dtors_atexit = true;
+    }
+
+    auto head = static_cast<DtorList*>(std::malloc(sizeof(DtorList)));
+    if (!head) {
+      return -1;
+    }
+
+    head->dtor = dtor;
+    head->obj = obj;
+    head->next = static_cast<DtorList*>(pthread_getspecific(dtors));
+
+    if (pthread_setspecific(dtors, head) != 0) {
+      std::free(head);
+      return -1;
+    }
 
-_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*dtor)(void *), void *obj,
-                                            void *dso_symbol) throw() {
-  extern int __cxa_thread_atexit_impl(void (*)(void *), void *, void *);
-  return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
+    return 0;
+  }
 }
 
-#endif // HAVE__CXA_THREAD_ATEXIT_IMPL
-
 } // extern "C"
 } // namespace __cxxabiv1
Index: src/CMakeLists.txt
===================================================================
--- src/CMakeLists.txt
+++ src/CMakeLists.txt
@@ -41,10 +41,6 @@
 
 include_directories("${LIBCXXABI_LIBCXX_INCLUDES}")
 
-if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL)
-  add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL)
-endif()
-
 # Generate library list
 set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES})
 
Index: cmake/config-ix.cmake
===================================================================
--- cmake/config-ix.cmake
+++ cmake/config-ix.cmake
@@ -43,5 +43,3 @@
 check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB)
 check_library_exists(pthread pthread_once "" LIBCXXABI_HAS_PTHREAD_LIB)
 check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXXABI_HAS_GCC_S_LIB)
-check_library_exists(c __cxa_thread_atexit_impl ""
-  LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to