tavianator created this revision.
tavianator added reviewers: danalbert, jroelofs.
tavianator added a subscriber: cfe-commits.
Herald added subscribers: danalbert, tberghammer.

__cxa_thread_atexit_impl() isn't present on all platforms, for example
Android pre-6.0.  This patch uses a weak symbol to detect _impl() 
support, falling back to a pthread_key_t-based implementation.

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
@@ -8,19 +8,77 @@
 //===----------------------------------------------------------------------===//
 
 #include "cxxabi.h"
+#include <cstdlib>
+#include <pthread.h>
 
 namespace __cxxabiv1 {
-extern "C" {
+namespace {
+  typedef void (*Dtor)(void *);
+
+  struct DtorList {
+    Dtor dtor;
+    void* obj;
+    DtorList* next;
+  };
+
+  void run_dtors(void* ptr) {
+    auto elem = static_cast<DtorList*>(ptr);
+    while (elem) {
+      auto saved = elem;
+      elem = elem->next;
+      saved->dtor(saved->obj);
+      std::free(saved);
+    }
+  }
+
+  class DtorListHolder {
+  public:
+    DtorListHolder() {
+      pthread_key_create(&key_, run_dtors);
+    }
+
+    ~DtorListHolder() {
+      run_dtors(get());
+      pthread_key_delete(key_);
+    }
+
+    DtorList* get() {
+      return static_cast<DtorList*>(pthread_getspecific(key_));
+    }
+
+    void set(DtorList* list) {
+      pthread_setspecific(key_, list);
+    }
+
+  private:
+    pthread_key_t key_;
+  };
+} // namespace
 
-#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
+extern "C" {
 
-_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*dtor)(void *), void *obj,
+_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, 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);
-}
+  extern int __cxa_thread_atexit_impl(Dtor, void *, void *)
+    __attribute__((__weak__));
 
-#endif // HAVE__CXA_THREAD_ATEXIT_IMPL
+  if (__cxa_thread_atexit_impl) {
+    return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
+  } else {
+    static DtorListHolder dtors;
+
+    auto head = static_cast<DtorList*>(std::malloc(sizeof(DtorList)));
+    if (!head) {
+      return -1;
+    }
+
+    head->dtor = dtor;
+    head->obj = obj;
+    head->next = dtors.get();
+    dtors.set(head);
+    return 0;
+  }
+}
 
 } // 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