asan/tsan: improve SpinMutex


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159518 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index 6cc86d3..ca3e2f9 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -14,8 +14,9 @@
 #ifndef SANITIZER_MUTEX_H
 #define SANITIZER_MUTEX_H
 
-#include "sanitizer_internal_defs.h"
 #include "sanitizer_atomic.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
 
 namespace __sanitizer {
 
@@ -26,8 +27,9 @@
   }
 
   void Lock() {
-    while (atomic_exchange(&state_, 1, memory_order_acquire))
-      proc_yield(10);
+    if (atomic_exchange(&state_, 1, memory_order_acquire) == 0)
+      return;
+    LockSlow();
   }
 
   void Unlock() {
@@ -37,6 +39,18 @@
  private:
   atomic_uint8_t state_;
 
+  void NOINLINE LockSlow() {
+    for (int i = 0;; i++) {
+      if (i < 10)
+        proc_yield(10);
+      else
+        internal_sched_yield();
+      if (atomic_load(&state_, memory_order_relaxed) == 0
+          && atomic_exchange(&state_, 1, memory_order_acquire) == 0)
+        return;
+    }
+  }
+
   SpinMutex(const SpinMutex&);
   void operator=(const SpinMutex&);
 };