[compiler-rt] r202120 - [sanitizer] add support for try_lock in deadlock detector

Kostya Serebryany kcc at google.com
Tue Feb 25 00:24:15 PST 2014


Author: kcc
Date: Tue Feb 25 02:24:15 2014
New Revision: 202120

URL: http://llvm.org/viewvc/llvm-project?rev=202120&view=rev
Log:
[sanitizer] add support for try_lock in deadlock detector

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h
    compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.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=202120&r1=202119&r2=202120&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 25 02:24:15 2014
@@ -143,6 +143,18 @@ class DeadlockDetector {
     return is_reachable;
   }
 
+  // Handles the try_lock event, returns false.
+  // When a try_lock event happens (i.e. a try_lock call succeeds) we need
+  // to add this lock to the currently held locks, but we should not try to
+  // change the lock graph or to detect a cycle.  We may want to investigate
+  // whether a more aggressive strategy is possible for try_lock.
+  bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+    ensureCurrentEpoch(dtls);
+    uptr cur_idx = nodeToIndex(cur_node);
+    dtls->addLock(cur_idx, current_epoch_);
+    return false;
+  }
+
   // Finds a path between the lock 'cur_node' (which is currently held in dtls)
   // and some other currently held lock, returns the length of the path
   // or 0 on failure.
@@ -170,8 +182,13 @@ class DeadlockDetector {
   }
 
   uptr testOnlyGetEpoch() const { return current_epoch_; }
+  bool testOnlyHasEdge(uptr l1, uptr l2) {
+    return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2));
+  }
   // idx1 and idx2 are raw indices to g_, not lock IDs.
-  bool testOnlyHasEdge(uptr idx1, uptr idx2) { return g_.hasEdge(idx1, idx2); }
+  bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) {
+    return g_.hasEdge(idx1, idx2);
+  }
 
   void Print() {
     for (uptr from = 0; from < size(); from++)

Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc?rev=202120&r1=202119&r2=202120&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc Tue Feb 25 02:24:15 2014
@@ -301,14 +301,41 @@ void RunCorrectEpochFlush() {
   EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
   d.onLock(&dtls, l0);
   d.onLock(&dtls, l1);
-  EXPECT_TRUE(d.testOnlyHasEdge(0, 1));
-  EXPECT_FALSE(d.testOnlyHasEdge(1, 0));
-  EXPECT_FALSE(d.testOnlyHasEdge(3, 0));
-  EXPECT_FALSE(d.testOnlyHasEdge(4, 0));
-  EXPECT_FALSE(d.testOnlyHasEdge(5, 0));
+  EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
 }
 
 TEST(DeadlockDetector, CorrectEpochFlush) {
   RunCorrectEpochFlush<BV1>();
   RunCorrectEpochFlush<BV2>();
 }
+
+template <class BV>
+void RunTryLockTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  uptr l2 = d.newNode(0);
+  EXPECT_FALSE(d.onLock(&dtls, l0));
+  EXPECT_FALSE(d.onTryLock(&dtls, l1));
+  EXPECT_FALSE(d.onLock(&dtls, l2));
+  EXPECT_TRUE(d.isHeld(&dtls, l0));
+  EXPECT_TRUE(d.isHeld(&dtls, l1));
+  EXPECT_TRUE(d.isHeld(&dtls, l2));
+  EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
+  EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
+  d.onUnlock(&dtls, l0);
+  d.onUnlock(&dtls, l1);
+  d.onUnlock(&dtls, l2);
+}
+
+TEST(DeadlockDetector, TryLockTest) {
+  RunTryLockTest<BV1>();
+  RunTryLockTest<BV2>();
+}

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=202120&r1=202119&r2=202120&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Tue Feb 25 02:24:15 2014
@@ -960,7 +960,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_tryl
   if (res == EOWNERDEAD)
     MutexRepair(thr, pc, (uptr)m);
   if (res == 0 || res == EOWNERDEAD)
-    MutexLock(thr, pc, (uptr)m);
+    MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
   return res;
 }
 
@@ -1004,7 +1004,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_trylo
   SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
   int res = REAL(pthread_spin_trylock)(m);
   if (res == 0) {
-    MutexLock(thr, pc, (uptr)m);
+    MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
   }
   return res;
 }

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=202120&r1=202119&r2=202120&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Tue Feb 25 02:24:15 2014
@@ -728,7 +728,8 @@ void ProcessPendingSignals(ThreadState *
 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
                  bool rw, bool recursive, bool linker_init);
 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1,
+               bool try_lock = false);
 int  MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);

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=202120&r1=202119&r2=202120&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 25 02:24:15 2014
@@ -92,7 +92,7 @@ void MutexDestroy(ThreadState *thr, uptr
   DestroyAndFree(s);
 }
 
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
   Context *ctx = CTX();
   DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
   CHECK_GT(rec, 0);
@@ -128,8 +128,11 @@ void MutexLock(ThreadState *thr, uptr pc
       Printf("ThreadSanitizer: reursive-lock\n");
     }
     // Printf("MutexLock: %zx\n", s->deadlock_detector_id);
-    bool has_deadlock =
-        ctx->dd.onLock(&thr->deadlock_detector_tls, s->deadlock_detector_id);
+    bool has_deadlock = try_lock
+                            ? ctx->dd.onTryLock(&thr->deadlock_detector_tls,
+                                                s->deadlock_detector_id)
+                            : ctx->dd.onLock(&thr->deadlock_detector_tls,
+                                             s->deadlock_detector_id);
     if (has_deadlock) {
       uptr path[10];
       uptr len = ctx->dd.findPathToHeldLock(&thr->deadlock_detector_tls,

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=202120&r1=202119&r2=202120&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 25 02:24:15 2014
@@ -14,6 +14,7 @@ class PaddedLock {
   }
   void lock() { assert(0 == pthread_mutex_lock(&mu_)); }
   void unlock() { assert(0 == pthread_mutex_unlock(&mu_)); }
+  bool try_lock() { return 0 == pthread_mutex_trylock(&mu_); }
 
  private:
   pthread_mutex_t mu_;
@@ -38,6 +39,11 @@ class LockTest {
     return &locks_[i];
   }
 
+  bool T(size_t i) {
+    assert(i < n_);
+    return locks_[i].try_lock();
+  }
+
   // Simple lock order onversion.
   void Test1() {
     fprintf(stderr, "Starting Test1\n");
@@ -114,6 +120,34 @@ class LockTest {
                &LockTest::Lock1_Loop_2);
   }
 
+  void Test7() {
+    fprintf(stderr, "Starting Test7\n");
+    // CHECK: Starting Test7
+    L(0); T(1); U(1); U(0);
+    T(1); L(0); U(1); U(0);
+    // CHECK-NOT: WARNING: ThreadSanitizer:
+    fprintf(stderr, "No cycle: 0=>1\n");
+    // CHECK: No cycle: 0=>1
+
+    T(2); L(3); U(3); U(2);
+    L(3); T(2); U(3); U(2);
+    // CHECK-NOT: WARNING: ThreadSanitizer:
+    fprintf(stderr, "No cycle: 2=>3\n");
+    // CHECK: No cycle: 2=>3
+
+    T(4); L(5); U(4); U(5);
+    L(5); L(4); U(4); U(5);
+    // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+    fprintf(stderr, "Have cycle: 4=>5\n");
+    // CHECK: Have cycle: 4=>5
+
+    L(7); L(6); U(6); U(7);
+    T(6); L(7); U(6); U(7);
+    // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+    fprintf(stderr, "Have cycle: 6=>7\n");
+    // CHECK: Have cycle: 6=>7
+  }
+
  private:
   void Lock2(size_t l1, size_t l2) { L(l1); L(l2); U(l2); U(l1); }
   void Lock_0_1() { Lock2(0, 1); }
@@ -177,6 +211,7 @@ int main() {
   { LockTest t(5); t.Test4(); }
   { LockTest t(5); t.Test5(); }
   { LockTest t(5); t.Test6(); }
+  { LockTest t(10); t.Test7(); }
   fprintf(stderr, "DONE\n");
   // CHECK: DONE
 }





More information about the llvm-commits mailing list