[compiler-rt] r201572 - [sanitizer] make sure the deadlock detector survives the change of epochs; add a test and a comment

Kostya Serebryany kcc at google.com
Tue Feb 18 05:41:50 PST 2014


Author: kcc
Date: Tue Feb 18 07:41:49 2014
New Revision: 201572

URL: http://llvm.org/viewvc/llvm-project?rev=201572&view=rev
Log:
[sanitizer] make sure the deadlock detector survives the change of epochs; add a test and a comment

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
    compiler-rt/trunk/test/tsan/deadlock_detector_stress_test.cc

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h?rev=201572&r1=201571&r2=201572&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h Tue Feb 18 07:41:49 2014
@@ -12,6 +12,13 @@
 // When a lock event happens, the detector checks if the locks already held by
 // the current thread are reachable from the newly acquired lock.
 //
+// The detector can handle only a fixed amount of simultaneously live locks
+// (a lock is alive if it has been locked at least once and has not been
+// destroyed). When the maximal number of locks is reached the entire graph
+// is flushed and the new lock epoch is started. The node ids from the old
+// epochs can not be used with any of the detector methods except for
+// nodeBelongsToCurrentEpoch().
+//
 // FIXME: this is work in progress, nothing really works yet.
 //
 //===----------------------------------------------------------------------===//
@@ -37,6 +44,7 @@ class DeadlockDetectorTLS {
 
   void addLock(uptr lock_id, uptr current_epoch) {
     // Printf("addLock: %zx %zx\n", lock_id, current_epoch);
+    CHECK_LE(epoch_, current_epoch);
     if (current_epoch != epoch_)  {
       bv_.clear();
       epoch_ = current_epoch;
@@ -46,11 +54,12 @@ class DeadlockDetectorTLS {
 
   void removeLock(uptr lock_id, uptr current_epoch) {
     // Printf("remLock: %zx %zx\n", lock_id, current_epoch);
+    CHECK_LE(epoch_, current_epoch);
     if (current_epoch != epoch_)  {
       bv_.clear();
       epoch_ = current_epoch;
     }
-    CHECK(bv_.clearBit(lock_id));
+    bv_.clearBit(lock_id);  // May already be cleared due to epoch update.
   }
 
   const BV &getLocks() const { return bv_; }
@@ -107,6 +116,10 @@ class DeadlockDetector {
   // Get data associated with the node created by newNode().
   uptr getData(uptr node) const { return data_[nodeToIndex(node)]; }
 
+  bool nodeBelongsToCurrentEpoch(uptr node) {
+    return node && (node / size() * size()) == current_epoch_;
+  }
+
   void removeNode(uptr node) {
     uptr idx = nodeToIndex(node);
     CHECK(!available_nodes_.getBit(idx));

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=201572&r1=201571&r2=201572&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Tue Feb 18 07:41:49 2014
@@ -25,7 +25,7 @@ namespace __tsan {
 static __sanitizer::DeadlockDetector<DDBV> g_deadlock_detector;
 
 static void EnsureDeadlockDetectorID(ThreadState *thr, SyncVar *s) {
-  if (!s->deadlock_detector_id)
+  if (!g_deadlock_detector.nodeBelongsToCurrentEpoch(s->deadlock_detector_id))
     s->deadlock_detector_id =
         g_deadlock_detector.newNode(reinterpret_cast<uptr>(s));
 }
@@ -62,7 +62,7 @@ void MutexDestroy(ThreadState *thr, uptr
   if (s == 0)
     return;
   if (common_flags()->detect_deadlocks) {
-    if (s->deadlock_detector_id)
+    if (g_deadlock_detector.nodeBelongsToCurrentEpoch(s->deadlock_detector_id))
       g_deadlock_detector.removeNode(s->deadlock_detector_id);
     s->deadlock_detector_id = 0;
   }
@@ -121,12 +121,11 @@ void MutexLock(ThreadState *thr, uptr pc
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
   if (common_flags()->detect_deadlocks) {
     EnsureDeadlockDetectorID(thr, s);
+    // Printf("MutexLock: %zx\n", s->deadlock_detector_id);
     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)"
-               : "");
+    if (has_deadlock)
+      Printf("ThreadSanitizer: lock-order-inversion (potential deadlock)\n");
   }
   s->mtx.Unlock();
 }

Modified: compiler-rt/trunk/test/tsan/deadlock_detector_stress_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/deadlock_detector_stress_test.cc?rev=201572&r1=201571&r2=201572&view=diff
==============================================================================
--- compiler-rt/trunk/test/tsan/deadlock_detector_stress_test.cc (original)
+++ compiler-rt/trunk/test/tsan/deadlock_detector_stress_test.cc Tue Feb 18 07:41:49 2014
@@ -60,16 +60,38 @@ class LockTest {
     fprintf(stderr, "Starting Test3\n");
     // CHECK: Starting Test3
     L(0); L(1); U(0); U(1);
+    L(2);
     CreateAndDestroyManyLocks();
+    U(2);
     L(1); L(0); U(0); U(1);
     // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
     // CHECK-NOT: ThreadSanitizer:
   }
 
+  // lock l0=>l1; then create and use lots of locks; then lock l1=>l0.
+  // The deadlock epoch should have changed and we should not report anything.
+  void Test4() {
+    fprintf(stderr, "Starting Test4\n");
+    // CHECK: Starting Test4
+    L(0); L(1); U(0); U(1);
+    L(2);
+    CreateLockUnlockAndDestroyManyLocks();
+    U(2);
+    L(1); L(0); U(0); U(1);
+    // CHECK-NOT: ThreadSanitizer:
+  }
+
  private:
   void CreateAndDestroyManyLocks() {
     PaddedLock create_many_locks_but_never_acquire[kDeadlockGraphSize];
   }
+  void CreateLockUnlockAndDestroyManyLocks() {
+    PaddedLock many_locks[kDeadlockGraphSize];
+    for (size_t i = 0; i < kDeadlockGraphSize; i++) {
+      many_locks[i].lock();
+      many_locks[i].unlock();
+    }
+  }
   static const size_t kDeadlockGraphSize = 4096;
   size_t n_;
   PaddedLock *locks_;
@@ -79,6 +101,7 @@ int main() {
   { LockTest t(5); t.Test1(); }
   { LockTest t(5); t.Test2(); }
   { LockTest t(5); t.Test3(); }
+  { LockTest t(5); t.Test4(); }
   fprintf(stderr, "DONE\n");
   // CHECK: DONE
 }





More information about the llvm-commits mailing list