[sanitizer] Move the PTHREAD_DESTRUCTOR_ITERATIONS constant to sanitizer_linux.h.

Add a test.

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@192442 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index 454b556..e169191 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/lib/lsan/lsan_interceptors.cc
@@ -192,9 +192,6 @@
   atomic_uintptr_t tid;
 };
 
-// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
-const uptr kPthreadDestructorIterations = 4;
-
 extern "C" void *__lsan_thread_start_func(void *arg) {
   ThreadParam *p = (ThreadParam*)arg;
   void* (*callback)(void *arg) = p->callback;
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 4c0450e..af7f2f5 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -77,6 +77,8 @@
 // Call cb for each region mapped by map.
 void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
 
+// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
+const uptr kPthreadDestructorIterations = 4;
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
index 592d9c3..95ce09b 100644
--- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -255,6 +255,42 @@
     }
 }
 
+pthread_key_t key;
+bool destructor_executed;
+
+extern "C"
+void destructor(void *arg) {
+  uptr iter = reinterpret_cast<uptr>(arg);
+  if (iter > 1) {
+    ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1)));
+    return;
+  }
+  destructor_executed = true;
+}
+
+extern "C"
+void *thread_func(void *arg) {
+  return reinterpret_cast<void*>(pthread_setspecific(key, arg));
+}
+
+void SpawnThread(uptr iteration) {
+  destructor_executed = false;
+  pthread_t tid;
+  ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func,
+                              reinterpret_cast<void *>(iteration)));
+  void *retval;
+  ASSERT_EQ(0, pthread_join(tid, &retval));
+  ASSERT_EQ(0, retval);
+}
+
+TEST(SanitizerCommon, PthreadDestructorIterations) {
+  ASSERT_EQ(0, pthread_key_create(&key, &destructor));
+  SpawnThread(kPthreadDestructorIterations);
+  EXPECT_TRUE(destructor_executed);
+  SpawnThread(kPthreadDestructorIterations + 1);
+  EXPECT_FALSE(destructor_executed);
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LINUX
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 7058f43..68b23b5 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -853,7 +853,8 @@
   {
     ThreadState *thr = cur_thread();
     ScopedInRtl in_rtl;
-    if (pthread_setspecific(g_thread_finalize_key, (void*)4)) {
+    if (pthread_setspecific(g_thread_finalize_key,
+                            (void *)kPthreadDestructorIterations)) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
     }