tsan/asan: add SpinMutex to sanitizer_common


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159439 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h
index df3344e..135be18 100644
--- a/lib/sanitizer_common/sanitizer_atomic.h
+++ b/lib/sanitizer_common/sanitizer_atomic.h
@@ -6,6 +6,10 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef SANITIZER_ATOMIC_H
 #define SANITIZER_ATOMIC_H
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index c4e4f7f..8bb9d36 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -6,6 +6,10 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
 
 #ifndef SANITIZER_MUTEX_H
 #define SANITIZER_MUTEX_H
@@ -15,6 +19,28 @@
 
 namespace __sanitizer {
 
+class SpinMutex {
+ public:
+  SpinMutex() {
+    atomic_store(&state_, 0, memory_order_relaxed);
+  }
+
+  void Lock() {
+    while (atomic_exchange(&state_, 1, memory_order_acquire))
+      proc_yield(10);
+  }
+
+  void Unlock() {
+    atomic_store(&state_, 0, memory_order_release);
+  }
+
+ private:
+  atomic_uint8_t state_;
+
+  SpinMutex(const SpinMutex&);
+  void operator=(const SpinMutex&);
+};
+
 template<typename MutexType>
 class GenericScopedLock {
  public:
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
index ba63643..e8da03e 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
@@ -124,6 +124,7 @@
   }
 
   a.TestOnlyUnmap();
+  (void)sink;
 }
 
 void FailInAssertionOnOOM() {
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index 2a73947..d6c7f56 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -7,14 +7,14 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is a part of ThreadSanitizer (TSan), a race detector.
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
 //
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_common.h"
 #include "gtest/gtest.h"
 #include <stdlib.h>
 
-namespace __tsan {
+namespace __sanitizer {
 
 TEST(Allocator, Basic) {
   char *p = (char*)InternalAlloc(10);
@@ -53,4 +53,4 @@
   }
 }
 
-}  // namespace __tsan
+}  // namespace __sanitizer
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index 1db2efc..a0e83b6 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -3,12 +3,12 @@
 CXXFLAGS = -fPIE -g -Wall -Werror -DTSAN_DEBUG=$(DEBUG)
 # Silence warnings that Clang produces for gtest code.
 # Use -Wno-attributes so that gcc doesn't complain about unknown warning types.
-CXXFLAGS += -Wno-static-in-inline -Wno-attributes
+CXXFLAGS += -Wno-attributes
 ifeq ($(DEBUG), 0)
 	CXXFLAGS += -O3
 endif
 ifeq ($(CXX), clang++)
-  CXXFLAGS+= -Wno-unused-private-field
+  CXXFLAGS+= -Wno-unused-private-field -Wno-static-in-inline
 endif
 
 LIBTSAN=rtl/libtsan.a
diff --git a/lib/tsan/unit_tests/tsan_mutex_test.cc b/lib/tsan/unit_tests/tsan_mutex_test.cc
index e26dd48..9af3d8d 100644
--- a/lib/tsan/unit_tests/tsan_mutex_test.cc
+++ b/lib/tsan/unit_tests/tsan_mutex_test.cc
@@ -13,21 +13,23 @@
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_mutex.h"
 #include "tsan_mutex.h"
 #include "gtest/gtest.h"
 
 namespace __tsan {
 
+template<typename MutexType>
 class TestData {
  public:
-  TestData()
-    : mtx_(MutexTypeAnnotations, StatMtxAnnotations) {
+  TestData(MutexType *mtx)
+    : mtx_(mtx) {
     for (int i = 0; i < kSize; i++)
       data_[i] = 0;
   }
 
   void Write() {
-    Lock l(&mtx_);
+    Lock l(mtx_);
     T v0 = data_[0];
     for (int i = 0; i < kSize; i++) {
       CHECK_EQ(data_[i], v0);
@@ -36,17 +38,26 @@
   }
 
   void Read() {
-    ReadLock l(&mtx_);
+    ReadLock l(mtx_);
     T v0 = data_[0];
     for (int i = 0; i < kSize; i++) {
       CHECK_EQ(data_[i], v0);
     }
   }
 
+  void Backoff() {
+    volatile T data[kSize] = {};
+    for (int i = 0; i < kSize; i++) {
+      data[i]++;
+      CHECK_EQ(data[i], 1);
+    }
+  }
+
  private:
+  typedef GenericScopedLock<MutexType> Lock;
   static const int kSize = 64;
   typedef u64 T;
-  Mutex mtx_;
+  MutexType *mtx_;
   char pad_[kCacheLineSize];
   T data_[kSize];
 };
@@ -59,43 +70,55 @@
 const int kIters = 64*1024;
 #endif
 
+template<typename MutexType>
 static void *write_mutex_thread(void *param) {
-  TestData *data = (TestData *)param;
-  TestData local;
+  TestData<MutexType> *data = (TestData<MutexType>*)param;
   for (int i = 0; i < kIters; i++) {
     data->Write();
-    local.Write();
+    data->Backoff();
   }
   return 0;
 }
 
+template<typename MutexType>
 static void *read_mutex_thread(void *param) {
-  TestData *data = (TestData *)param;
-  TestData local;
+  TestData<MutexType> *data = (TestData<MutexType>*)param;
   for (int i = 0; i < kIters; i++) {
     if ((i % kWriteRate) == 0)
       data->Write();
     else
       data->Read();
-    local.Write();
+    data->Backoff();
   }
   return 0;
 }
 
 TEST(Mutex, Write) {
-  TestData data;
+  Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
+  TestData<Mutex> data(&mtx);
   pthread_t threads[kThreads];
   for (int i = 0; i < kThreads; i++)
-    pthread_create(&threads[i], 0, write_mutex_thread, &data);
+    pthread_create(&threads[i], 0, write_mutex_thread<Mutex>, &data);
   for (int i = 0; i < kThreads; i++)
     pthread_join(threads[i], 0);
 }
 
 TEST(Mutex, ReadWrite) {
-  TestData data;
+  Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
+  TestData<Mutex> data(&mtx);
   pthread_t threads[kThreads];
   for (int i = 0; i < kThreads; i++)
-    pthread_create(&threads[i], 0, read_mutex_thread, &data);
+    pthread_create(&threads[i], 0, read_mutex_thread<Mutex>, &data);
+  for (int i = 0; i < kThreads; i++)
+    pthread_join(threads[i], 0);
+}
+
+TEST(Mutex, SpinWrite) {
+  SpinMutex mtx;
+  TestData<SpinMutex> data(&mtx);
+  pthread_t threads[kThreads];
+  for (int i = 0; i < kThreads; i++)
+    pthread_create(&threads[i], 0, write_mutex_thread<SpinMutex>, &data);
   for (int i = 0; i < kThreads; i++)
     pthread_join(threads[i], 0);
 }