[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