[compiler-rt] r202132 - [sanitizer] support pthread_rwlock_rd* in deadlock detector

Kostya Serebryany kcc at google.com
Tue Feb 25 02:33:37 PST 2014


Author: kcc
Date: Tue Feb 25 04:33:37 2014
New Revision: 202132

URL: http://llvm.org/viewvc/llvm-project?rev=202132&view=rev
Log:
[sanitizer] support pthread_rwlock_rd* in deadlock detector

Modified:
    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/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=202132&r1=202131&r2=202132&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Tue Feb 25 04:33:37 2014
@@ -731,7 +731,7 @@ void MutexDestroy(ThreadState *thr, uptr
 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 MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false);
 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
 void MutexRepair(ThreadState *thr, uptr pc, uptr addr);  // call on EOWNERDEAD

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=202132&r1=202131&r2=202132&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 04:33:37 2014
@@ -29,8 +29,7 @@ static void EnsureDeadlockDetectorID(Con
   ctx->dd.ensureCurrentEpoch(&thr->deadlock_detector_tls);
 }
 
-static void DDUnlock(Context *ctx, ThreadState *thr,
-                                     SyncVar *s) {
+static void DDUnlock(Context *ctx, ThreadState *thr, SyncVar *s) {
   if (!common_flags()->detect_deadlocks) return;
   Lock lk(&ctx->dd_mtx);
   EnsureDeadlockDetectorID(ctx, thr, s);
@@ -38,6 +37,38 @@ static void DDUnlock(Context *ctx, Threa
   ctx->dd.onUnlock(&thr->deadlock_detector_tls, s->deadlock_detector_id);
 }
 
+static void DDLock(Context *ctx, ThreadState *thr, SyncVar *s, uptr pc,
+                   bool try_lock) {
+  if (!common_flags()->detect_deadlocks) return;
+  Lock lk(&ctx->dd_mtx);
+  EnsureDeadlockDetectorID(ctx, thr, s);
+  if (ctx->dd.isHeld(&thr->deadlock_detector_tls, s->deadlock_detector_id)) {
+    // FIXME: add tests, handle the real recursive locks.
+    Printf("ThreadSanitizer: reursive-lock\n");
+  }
+  // Printf("MutexLock: %zx\n", 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,
+                                          s->deadlock_detector_id, path,
+                                          ARRAY_SIZE(path));
+    CHECK_GT(len, 0U);  // Hm.. cycle of 10 locks? I'd like to see that.
+    ThreadRegistryLock l(CTX()->thread_registry);
+    ScopedReport rep(ReportTypeDeadlock);
+    for (uptr i = 0; i < len; i++)
+      rep.AddMutex(reinterpret_cast<SyncVar*>(ctx->dd.getData(path[i])));
+    StackTrace trace;
+    trace.ObtainCurrent(thr, pc);
+    rep.AddStack(&trace);
+    OutputReport(CTX(), rep);
+  }
+}
+
 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
                  bool rw, bool recursive, bool linker_init) {
   Context *ctx = CTX();
@@ -129,35 +160,7 @@ void MutexLock(ThreadState *thr, uptr pc
   }
   s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
-  if (common_flags()->detect_deadlocks) {
-    Lock lk(&ctx->dd_mtx);
-    EnsureDeadlockDetectorID(ctx, thr, s);
-    if (ctx->dd.isHeld(&thr->deadlock_detector_tls, s->deadlock_detector_id)) {
-      // FIXME: add tests, handle the real recursive locks.
-      Printf("ThreadSanitizer: reursive-lock\n");
-    }
-    // Printf("MutexLock: %zx\n", 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,
-                                         s->deadlock_detector_id, path,
-                                         ARRAY_SIZE(path));
-      CHECK_GT(len, 0U);  // Hm.. cycle of 10 locks? I'd like to see that.
-      ThreadRegistryLock l(CTX()->thread_registry);
-      ScopedReport rep(ReportTypeDeadlock);
-      for (uptr i = 0; i < len; i++)
-        rep.AddMutex(reinterpret_cast<SyncVar*>(ctx->dd.getData(path[i])));
-      StackTrace trace;
-      trace.ObtainCurrent(thr, pc);
-      rep.AddStack(&trace);
-      OutputReport(CTX(), rep);
-    }
-  }
+  DDLock(ctx, thr, s, pc, try_lock);
   s->mtx.Unlock();
 }
 
@@ -200,7 +203,7 @@ int MutexUnlock(ThreadState *thr, uptr p
   return rec;
 }
 
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock) {
   DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexReadLock);
   if (IsAppMem(addr))
@@ -216,6 +219,7 @@ void MutexReadLock(ThreadState *thr, upt
   AcquireImpl(thr, pc, &s->clock);
   s->last_lock = thr->fast_state.raw();
   thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
+  DDLock(CTX(), thr, s, pc, try_lock);
   s->mtx.ReadUnlock();
 }
 

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=202132&r1=202131&r2=202132&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 04:33:37 2014
@@ -3,7 +3,7 @@
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock
 // RUN: TSAN_OPTIONS=detect_deadlocks=1 not %t 2>&1 | FileCheck %s
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock
-// RUN: TSAN_OPTIONS=detect_deadlocks=1 not %t 2>&1 | FileCheck %s
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD
 #include <pthread.h>
 #undef NDEBUG
 #include <assert.h>
@@ -16,9 +16,13 @@ class PthreadMutex {
     assert(0 == pthread_mutex_destroy(&mu_));
     (void)padding_;
   }
+  static bool supports_read_lock() { return false; }
   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_); }
+  void rdlock() { assert(0); }
+  void rdunlock() { assert(0); }
+  bool try_rdlock() { assert(0); }
 
  private:
   pthread_mutex_t mu_;
@@ -32,9 +36,13 @@ class PthreadSpinLock {
     assert(0 == pthread_spin_destroy(&mu_));
     (void)padding_;
   }
+  static bool supports_read_lock() { return false; }
   void lock() { assert(0 == pthread_spin_lock(&mu_)); }
   void unlock() { assert(0 == pthread_spin_unlock(&mu_)); }
   bool try_lock() { return 0 == pthread_spin_trylock(&mu_); }
+  void rdlock() { assert(0); }
+  void rdunlock() { assert(0); }
+  bool try_rdlock() { assert(0); }
 
  private:
   pthread_spinlock_t mu_;
@@ -48,9 +56,13 @@ class PthreadRWLock {
     assert(0 == pthread_rwlock_destroy(&mu_));
     (void)padding_;
   }
+  static bool supports_read_lock() { return true; }
   void lock() { assert(0 == pthread_rwlock_wrlock(&mu_)); }
   void unlock() { assert(0 == pthread_rwlock_unlock(&mu_)); }
   bool try_lock() { return 0 == pthread_rwlock_trywrlock(&mu_); }
+  void rdlock() { assert(0 == pthread_rwlock_rdlock(&mu_)); }
+  void rdunlock() { assert(0 == pthread_rwlock_unlock(&mu_)); }
+  bool try_rdlock() { return 0 == pthread_rwlock_tryrdlock(&mu_); }
 
  private:
   pthread_rwlock_t mu_;
@@ -65,11 +77,22 @@ class LockTest {
     assert(i < n_);
     locks_[i].lock();
   }
+
   void U(size_t i) {
     assert(i < n_);
     locks_[i].unlock();
   }
 
+  void RL(size_t i) {
+    assert(i < n_);
+    locks_[i].rdlock();
+  }
+
+  void RU(size_t i) {
+    assert(i < n_);
+    locks_[i].rdunlock();
+  }
+
   void *A(size_t i) {
     assert(i < n_);
     return &locks_[i];
@@ -184,6 +207,23 @@ class LockTest {
     // CHECK: Have cycle: 6=>7
   }
 
+  void Test8() {
+    if (!LockType::supports_read_lock()) return;
+    fprintf(stderr, "Starting Test8\n");
+    // CHECK-RD: Starting Test8
+    RL(0); L(1); RU(0); U(1);
+    L(1); RL(0); RU(0); U(1);
+    // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion
+    fprintf(stderr, "Have cycle: 0=>1\n");
+    // CHECK-RD: Have cycle: 0=>1
+
+    RL(2); RL(3); RU(2); RU(3);
+    RL(3); RL(2); RU(2); RU(3);
+    // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion
+    fprintf(stderr, "Have cycle: 2=>3\n");
+    // CHECK-RD: Have cycle: 2=>3
+  }
+
  private:
   void Lock2(size_t l1, size_t l2) { L(l1); L(l2); U(l2); U(l1); }
   void Lock_0_1() { Lock2(0, 1); }
@@ -250,6 +290,7 @@ int main () {
   { LockTest t(5); t.Test5(); }
   { LockTest t(5); t.Test6(); }
   { LockTest t(10); t.Test7(); }
+  { LockTest t(5); t.Test8(); }
   fprintf(stderr, "DONE\n");
   // CHECK: DONE
 }





More information about the llvm-commits mailing list