[compiler-rt] r201407 - [tsan] rudimentary support for deadlock detector in tsan (nothing really works yet except for a single tiny test). Also rename tsan's DeadlockDetector to InternalDeadlockDetector

Kostya Serebryany kcc at google.com
Fri Feb 14 04:20:43 PST 2014


Author: kcc
Date: Fri Feb 14 06:20:42 2014
New Revision: 201407

URL: http://llvm.org/viewvc/llvm-project?rev=201407&view=rev
Log:
[tsan] rudimentary support for deadlock detector in tsan (nothing really works yet except for a single tiny test). Also rename tsan's DeadlockDetector to InternalDeadlockDetector

Added:
    compiler-rt/trunk/lib/tsan/lit_tests/mutex_cycle2.c
Modified:
    compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h

Added: compiler-rt/trunk/lib/tsan/lit_tests/mutex_cycle2.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/mutex_cycle2.c?rev=201407&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/mutex_cycle2.c (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/mutex_cycle2.c Fri Feb 14 06:20:42 2014
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 %t 2>&1 | FileCheck %s
+#include <pthread.h>
+
+int main() {
+  pthread_mutex_t mu1, mu2;
+  pthread_mutex_init(&mu1, NULL);
+  pthread_mutex_init(&mu2, NULL);
+
+  // mu1 => mu2
+  pthread_mutex_lock(&mu1);
+  pthread_mutex_lock(&mu2);
+  pthread_mutex_unlock(&mu2);
+  pthread_mutex_unlock(&mu1);
+
+  // mu2 => mu1
+  pthread_mutex_lock(&mu2);
+  pthread_mutex_lock(&mu1);
+  // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+  pthread_mutex_unlock(&mu1);
+  pthread_mutex_unlock(&mu2);
+
+  pthread_mutex_destroy(&mu1);
+  pthread_mutex_destroy(&mu2);
+}

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.cc Fri Feb 14 06:20:42 2014
@@ -123,12 +123,12 @@ void InitializeMutex() {
 #endif
 }
 
-DeadlockDetector::DeadlockDetector() {
+InternalDeadlockDetector::InternalDeadlockDetector() {
   // Rely on zero initialization because some mutexes can be locked before ctor.
 }
 
 #if TSAN_DEBUG && !TSAN_GO
-void DeadlockDetector::Lock(MutexType t) {
+void InternalDeadlockDetector::Lock(MutexType t) {
   // Printf("LOCK %d @%zu\n", t, seq_ + 1);
   CHECK_GT(t, MutexTypeInvalid);
   CHECK_LT(t, MutexTypeCount);
@@ -155,7 +155,7 @@ void DeadlockDetector::Lock(MutexType t)
   }
 }
 
-void DeadlockDetector::Unlock(MutexType t) {
+void InternalDeadlockDetector::Unlock(MutexType t) {
   // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
   CHECK(locked_[t]);
   locked_[t] = 0;
@@ -210,7 +210,7 @@ Mutex::~Mutex() {
 
 void Mutex::Lock() {
 #if TSAN_DEBUG && !TSAN_GO
-  cur_thread()->deadlock_detector.Lock(type_);
+  cur_thread()->internal_deadlock_detector.Lock(type_);
 #endif
   uptr cmp = kUnlocked;
   if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
@@ -235,13 +235,13 @@ void Mutex::Unlock() {
   (void)prev;
   DCHECK_NE(prev & kWriteLock, 0);
 #if TSAN_DEBUG && !TSAN_GO
-  cur_thread()->deadlock_detector.Unlock(type_);
+  cur_thread()->internal_deadlock_detector.Unlock(type_);
 #endif
 }
 
 void Mutex::ReadLock() {
 #if TSAN_DEBUG && !TSAN_GO
-  cur_thread()->deadlock_detector.Lock(type_);
+  cur_thread()->internal_deadlock_detector.Lock(type_);
 #endif
   uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
   if ((prev & kWriteLock) == 0)
@@ -263,7 +263,7 @@ void Mutex::ReadUnlock() {
   DCHECK_EQ(prev & kWriteLock, 0);
   DCHECK_GT(prev & ~kWriteLock, 0);
 #if TSAN_DEBUG && !TSAN_GO
-  cur_thread()->deadlock_detector.Unlock(type_);
+  cur_thread()->internal_deadlock_detector.Unlock(type_);
 #endif
 }
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_mutex.h Fri Feb 14 06:20:42 2014
@@ -65,9 +65,9 @@ class Mutex {
 typedef GenericScopedLock<Mutex> Lock;
 typedef GenericScopedReadLock<Mutex> ReadLock;
 
-class DeadlockDetector {
+class InternalDeadlockDetector {
  public:
-  DeadlockDetector();
+  InternalDeadlockDetector();
   void Lock(MutexType t);
   void Unlock(MutexType t);
  private:

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Fri Feb 14 06:20:42 2014
@@ -30,6 +30,7 @@
 #include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_asm.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_deadlock_detector.h"
 #include "sanitizer_common/sanitizer_libignore.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
@@ -449,7 +450,8 @@ struct ThreadState {
   const uptr tls_size;
   ThreadContext *tctx;
 
-  DeadlockDetector deadlock_detector;
+  InternalDeadlockDetector internal_deadlock_detector;
+  __sanitizer::DeadlockDetectorTLS deadlock_detector_tls;
 
   bool in_signal_handler;
   SignalContext *signal_ctx;

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Fri Feb 14 06:20:42 2014
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <sanitizer_common/sanitizer_deadlock_detector.h>
+
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
 #include "tsan_sync.h"
@@ -20,6 +22,14 @@
 
 namespace __tsan {
 
+static __sanitizer::DeadlockDetector<TwoLevelBitVector<> > g_deadlock_detector;
+
+static void EnsureDeadlockDetectorID(ThreadState *thr, SyncVar *s) {
+  if (!s->deadlock_detector_id)
+    s->deadlock_detector_id =
+        g_deadlock_detector.newNode(reinterpret_cast<uptr>(s));
+}
+
 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
                  bool rw, bool recursive, bool linker_init) {
   Context *ctx = CTX();
@@ -35,6 +45,10 @@ void MutexCreate(ThreadState *thr, uptr
   s->is_rw = rw;
   s->is_recursive = recursive;
   s->is_linker_init = linker_init;
+  if (common_flags()->detect_deadlocks) {
+    EnsureDeadlockDetectorID(thr, s);
+    Printf("MutexCreate: %zx\n", s->deadlock_detector_id);
+  }
   s->mtx.Unlock();
 }
 
@@ -51,6 +65,10 @@ void MutexDestroy(ThreadState *thr, uptr
   SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
   if (s == 0)
     return;
+  if (common_flags()->detect_deadlocks) {
+    EnsureDeadlockDetectorID(thr, s);
+    Printf("MutexDestroy: %zx\n", s->deadlock_detector_id);
+  }
   if (IsAppMem(addr)) {
     CHECK(!thr->is_freeing);
     thr->is_freeing = true;
@@ -104,6 +122,15 @@ void MutexLock(ThreadState *thr, uptr pc
   }
   s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
+  if (common_flags()->detect_deadlocks) {
+    EnsureDeadlockDetectorID(thr, s);
+    bool has_deadlock = g_deadlock_detector.onLock(&thr->deadlock_detector_tls,
+                                                   s->deadlock_detector_id);
+    Printf("MutexLock: %zx;%s\n", s->deadlock_detector_id,
+           has_deadlock
+               ? " ThreadSanitizer: lock-order-inversion (potential deadlock)"
+               : "");
+  }
   s->mtx.Unlock();
 }
 
@@ -140,6 +167,12 @@ int MutexUnlock(ThreadState *thr, uptr p
     }
   }
   thr->mset.Del(s->GetId(), true);
+  if (common_flags()->detect_deadlocks) {
+    EnsureDeadlockDetectorID(thr, s);
+    Printf("MutexUnlock: %zx\n", s->deadlock_detector_id);
+    g_deadlock_detector.onUnlock(&thr->deadlock_detector_tls,
+                                 s->deadlock_detector_id);
+  }
   s->mtx.Unlock();
   return rec;
 }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc Fri Feb 14 06:20:42 2014
@@ -62,6 +62,7 @@ SyncVar* SyncTab::Create(ThreadState *th
   void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
   const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
   SyncVar *res = new(mem) SyncVar(addr, uid);
+  res->deadlock_detector_id = 0;
 #ifndef TSAN_GO
   res->creation_stack_id = CurrentStackId(thr, pc);
 #endif

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h?rev=201407&r1=201406&r2=201407&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h Fri Feb 14 06:20:42 2014
@@ -61,6 +61,7 @@ struct SyncVar {
   SyncClock read_clock;  // Used for rw mutexes only.
   u32 creation_stack_id;
   int owner_tid;  // Set only by exclusive owners.
+  uptr deadlock_detector_id;
   u64 last_lock;
   int recursion;
   bool is_rw;





More information about the llvm-commits mailing list