Merge "Add bionic-unit-tests-gcc{32,64}, compiled with gcc."
diff --git a/libc/Android.bp b/libc/Android.bp
index 513da1b..74fd22b 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -831,8 +831,9 @@
 cc_library_static {
     defaults: ["libc_defaults"],
     srcs: [
-        // The fork implementation depends on pthread data, so we can't include
-        // it in libc_ndk.a.
+        // The following implementations depend on pthread data, so we can't
+        // include them in libc_ndk.a.
+        "bionic/__cxa_thread_atexit_impl.cpp",
         "bionic/fork.cpp",
 
         // The data that backs getauxval is initialized in the libc init
@@ -1454,22 +1455,6 @@
     name: "libc_bionic_ndk",
 }
 
-cc_library_static {
-    name: "libc_thread_atexit_impl",
-    defaults: ["libc_defaults"],
-    srcs: ["bionic/__cxa_thread_atexit_impl.cpp"],
-    cflags: ["-Wframe-larger-than=2048"],
-    cppflags: ["-Wold-style-cast"],
-    include_dirs: ["bionic/libstdc++/include"],
-
-    arch: {
-        arm64: {
-            // b/25662915, clang compiled __cxa_thread_atexit_impl.cpp still failed.
-            clang: false,
-        },
-    },
-}
-
 // ========================================================
 // libc_pthread.a - pthreads parts that previously lived in
 // libc_bionic.a. Relocated to their own library because
@@ -1665,7 +1650,6 @@
         "libc_pthread",
         "libc_stack_protector",
         "libc_syscalls",
-        "libc_thread_atexit_impl",
         "libc_tzcode",
     ],
 
diff --git a/libc/Android.mk b/libc/Android.mk
index 2d97f35..4182505 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -243,9 +243,11 @@
 
 libc_bionic_src_files :=
 
-# The fork implementation depends on pthread data, so we can't include it in
-# libc_ndk.a.
-libc_bionic_src_files += bionic/fork.cpp
+# The following implementations depend on pthread data, so we can't include
+# them in libc_ndk.a.
+libc_bionic_src_files += \
+    bionic/__cxa_thread_atexit_impl.cpp \
+    bionic/fork.cpp \
 
 # The data that backs getauxval is initialized in the libc init functions which
 # are invoked by the linker. If this file is included in libc_ndk.a, only one of
@@ -586,9 +588,6 @@
     bionic/pthread_sigmask.cpp \
     bionic/pthread_spinlock.cpp \
 
-libc_thread_atexit_impl_src_files := \
-    bionic/__cxa_thread_atexit_impl.cpp \
-
 libc_arch_static_src_files := \
     bionic/dl_iterate_phdr_static.cpp \
 
@@ -1045,24 +1044,6 @@
 $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_ndk_src_files))
 include $(BUILD_STATIC_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libc_thread_atexit_impl_src_files)
-LOCAL_CFLAGS := $(libc_common_cflags) -Wframe-larger-than=2048
-
-LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
-LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
-LOCAL_C_INCLUDES := $(libc_common_c_includes)
-LOCAL_MODULE := libc_thread_atexit_impl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_CXX_STL := none
-LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_SANITIZE := never
-LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
-
-# b/25662915, clang compiled __cxa_thread_atexit_impl.cpp still failed.
-LOCAL_CLANG_arm64 := false
-
-include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
 # libc_pthread.a - pthreads parts that previously lived in
@@ -1260,7 +1241,6 @@
     libc_pthread \
     libc_stack_protector \
     libc_syscalls \
-    libc_thread_atexit_impl \
     libc_tzcode \
 
 LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 0e427d3..0e903b9 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -15,6 +15,8 @@
  */
 #include <sys/cdefs.h>
 
+#include "pthread_internal.h"
+
 struct thread_local_dtor {
   void (*func) (void *);
   void *arg;
@@ -22,25 +24,24 @@
   thread_local_dtor* next;
 };
 
-static __thread thread_local_dtor* thread_local_dtors = nullptr;
-
 extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
   thread_local_dtor* dtor = new thread_local_dtor();
 
   dtor->func = func;
   dtor->arg = arg;
   dtor->dso_handle = dso_handle;
-  dtor->next = thread_local_dtors;
 
-  thread_local_dtors = dtor;
-
+  pthread_internal_t* thread = __get_thread();
+  dtor->next = thread->thread_local_dtors;
+  thread->thread_local_dtors = dtor;
   return 0;
 }
 
 extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() {
-  while (thread_local_dtors != nullptr) {
-    thread_local_dtor* current = thread_local_dtors;
-    thread_local_dtors = current->next;
+  pthread_internal_t* thread = __get_thread();
+  while (thread->thread_local_dtors != nullptr) {
+    thread_local_dtor* current = thread->thread_local_dtors;
+    thread->thread_local_dtors = current->next;
 
     current->func(current->arg);
     delete current;
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 8f1ee95..91e210e 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -54,6 +54,7 @@
 extern "C" int __system_properties_init(void);
 extern "C" int __set_tls(void* ptr);
 extern "C" int __set_tid_address(int* tid_address);
+extern "C" int __sinit(void);
 
 __LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
 
@@ -133,6 +134,9 @@
   __pthread_internal_add(main_thread);
 
   __system_properties_init(); // Requires 'environ'.
+  // Initialize stdio here to get rid of data races caused by lazy initialization.
+  // TODO: Remove other calls to __sinit().
+  __sinit();
 }
 
 __noreturn static void __early_abort(int line) {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index d5d62a7..f96e9d2 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -52,6 +52,8 @@
   THREAD_DETACHED
 };
 
+struct thread_local_dtor;
+
 struct pthread_internal_t {
   struct pthread_internal_t* next;
   struct pthread_internal_t* prev;
@@ -94,6 +96,8 @@
 
   size_t mmap_size;
 
+  thread_local_dtor* thread_local_dtors;
+
   void* tls[BIONIC_TLS_SLOTS];
 
   pthread_key_data_t key_data[BIONIC_PTHREAD_KEY_COUNT];
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index f6d3501..27d992b 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -159,7 +159,7 @@
   pthread_key_t key;
   ASSERT_EQ(0, pthread_key_create(&key, NULL));
 
-  size_t stack_size = 128 * 1024;
+  size_t stack_size = 640 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, stack);
   memset(stack, 0xff, stack_size);
@@ -217,13 +217,13 @@
     while (spin_flag_) {}
     return NULL;
   }
-  static volatile bool spin_flag_;
+  static std::atomic<bool> spin_flag_;
 };
 
 // It doesn't matter if spin_flag_ is used in several tests,
 // because it is always set to false after each test. Each thread
 // loops on spin_flag_ can find it becomes false at some time.
-volatile bool SpinFunctionHelper::spin_flag_ = false;
+std::atomic<bool> SpinFunctionHelper::spin_flag_;
 
 static void* JoinFn(void* arg) {
   return reinterpret_cast<void*>(pthread_join(reinterpret_cast<pthread_t>(arg), NULL));
@@ -416,6 +416,8 @@
   pthread_t t1;
   ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
   ASSERT_EQ(0, pthread_setname_np(t1, "short 2"));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t1, nullptr));
 }
 
 TEST(pthread, pthread_setname_np__no_such_thread) {
@@ -466,6 +468,8 @@
   ASSERT_EQ(0, pthread_getcpuclockid(t, &c));
   timespec ts;
   ASSERT_EQ(0, clock_gettime(c, &ts));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t, nullptr));
 }
 
 TEST(pthread, pthread_getcpuclockid__no_such_thread) {
@@ -534,7 +538,7 @@
   // http://b/11693195 --- pthread_join could return before the thread had actually exited.
   // If the joiner unmapped the thread's stack, that could lead to SIGSEGV in the thread.
   for (size_t i = 0; i < 1024; ++i) {
-    size_t stack_size = 64*1024;
+    size_t stack_size = 640*1024;
     void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 
     pthread_attr_t a;