[compiler-rt] r202401 - [sanitizer] do not acquire a global mutex in deadlock detector when dealing with Unlock (it is essentially a thread-local operation)

Kostya Serebryany kcc at google.com
Thu Feb 27 06:38:42 PST 2014


Author: kcc
Date: Thu Feb 27 08:38:42 2014
New Revision: 202401

URL: http://llvm.org/viewvc/llvm-project?rev=202401&view=rev
Log:
[sanitizer] do not acquire a global mutex in deadlock detector when dealing with Unlock (it is essentially a thread-local operation)

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_rtl_mutex.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=202401&r1=202400&r2=202401&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector.h Thu Feb 27 08:38:42 2014
@@ -48,16 +48,17 @@ class DeadlockDetectorTLS {
     epoch_ = current_epoch;
   }
 
+  uptr getEpoch() const { return epoch_; }
+
   void addLock(uptr lock_id, uptr current_epoch) {
     // Printf("addLock: %zx %zx\n", lock_id, current_epoch);
     CHECK_EQ(epoch_, current_epoch);
     CHECK(bv_.setBit(lock_id));
   }
 
-  void removeLock(uptr lock_id, uptr current_epoch) {
+  void removeLock(uptr lock_id) {
     // Printf("remLock: %zx %zx\n", lock_id, current_epoch);
-    CHECK_EQ(epoch_, current_epoch);
-    bv_.clearBit(lock_id);  // May already be cleared due to epoch update.
+    CHECK(bv_.clearBit(lock_id));
   }
 
   const BV &getLocks(uptr current_epoch) const {
@@ -75,7 +76,8 @@ class DeadlockDetectorTLS {
 // and one DeadlockDetectorTLS object per evey thread.
 // This class is not thread safe, all concurrent accesses should be guarded
 // by an external lock.
-// Not thread-safe, all accesses should be protected by an external lock.
+// Most of the methods of this class are not thread-safe (i.e. should
+// be protected by an external lock) unless explicitly told otherwise.
 template <class BV>
 class DeadlockDetector {
  public:
@@ -133,7 +135,7 @@ class DeadlockDetector {
   }
 
   // Handles the lock event, returns true if there is a cycle.
-  // FIXME: handle RW locks, recusive locks, etc.
+  // FIXME: handle RW locks, recursive locks, etc.
   bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
     ensureCurrentEpoch(dtls);
     uptr cur_idx = nodeToIndex(cur_node);
@@ -171,10 +173,11 @@ class DeadlockDetector {
     return res;
   }
 
-  // Handle the unlock event.
+  // Handle the unlock event. This operation is thread-safe
+  // as it only touches the dtls.
   void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
-    ensureCurrentEpoch(dtls);
-    dtls->removeLock(nodeToIndex(node), current_epoch_);
+    if (dtls->getEpoch() == nodeToEpoch(node))
+      dtls->removeLock(nodeToIndexUnchecked(node));
   }
 
   bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
@@ -202,7 +205,7 @@ class DeadlockDetector {
 
   void check_node(uptr node) const {
     CHECK_GE(node, size());
-    CHECK_EQ(current_epoch_, node / size() * size());
+    CHECK_EQ(current_epoch_, nodeToEpoch(node));
   }
 
   uptr indexToNode(uptr idx) const {
@@ -210,11 +213,15 @@ class DeadlockDetector {
     return idx + current_epoch_;
   }
 
+  uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
+
   uptr nodeToIndex(uptr node) const {
     check_node(node);
-    return node % size();
+    return nodeToIndexUnchecked(node);
   }
 
+  uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
+
   uptr getAvailableNode(uptr data) {
     uptr idx = available_nodes_.getAndClearFirstOne();
     data_[idx] = data;

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=202401&r1=202400&r2=202401&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 Thu Feb 27 08:38:42 2014
@@ -269,9 +269,8 @@ void RunMultipleEpochsTest() {
   EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
 
   // Can not handle the locks from the previous epoch.
-  // The user should update the lock id.
+  // The caller should update the lock id.
   EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
-  EXPECT_DEATH(d.onUnlock(&dtls, l1), "CHECK failed.*current_epoch_");
 }
 
 TEST(DeadlockDetector, MultipleEpochsTest) {

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=202401&r1=202400&r2=202401&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Thu Feb 27 08:38:42 2014
@@ -32,8 +32,6 @@ static void EnsureDeadlockDetectorID(Con
 static void DDUnlock(Context *ctx, ThreadState *thr, SyncVar *s) {
   if (!common_flags()->detect_deadlocks) return;
   if (s->recursion != 0) return;
-  Lock lk(&ctx->dd_mtx);
-  EnsureDeadlockDetectorID(ctx, thr, s);
   // Printf("T%d MutexUnlock: %zx; recursion %d\n", thr->tid,
   //        s->deadlock_detector_id, s->recursion);
   ctx->dd.onUnlock(&thr->deadlock_detector_tls, s->deadlock_detector_id);





More information about the llvm-commits mailing list