diff options
| author | Kostya Serebryany <kcc@google.com> | 2014-02-14 12:20:42 +0000 |
|---|---|---|
| committer | Kostya Serebryany <kcc@google.com> | 2014-02-14 12:20:42 +0000 |
| commit | a63632a5c6acd6e8865cb0ffc060be1321db7298 (patch) | |
| tree | 69957e8d6f0c9ee22ad72e2284c123d22fbba9b5 /compiler-rt/lib/tsan | |
| parent | 127e93e4dcd06d6b965f66ae8eeab6ddc651b759 (diff) | |
| download | bcm5719-llvm-a63632a5c6acd6e8865cb0ffc060be1321db7298.tar.gz bcm5719-llvm-a63632a5c6acd6e8865cb0ffc060be1321db7298.zip | |
[tsan] rudimentary support for deadlock detector in tsan (nothing really works yet except for a single tiny test). Also rename tsan's DeadlockDetector to InternalDeadlockDetector
llvm-svn: 201407
Diffstat (limited to 'compiler-rt/lib/tsan')
| -rw-r--r-- | compiler-rt/lib/tsan/lit_tests/mutex_cycle2.c | 25 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_mutex.cc | 14 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_mutex.h | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.h | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc | 33 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_sync.cc | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_sync.h | 1 |
7 files changed, 72 insertions, 10 deletions
diff --git a/compiler-rt/lib/tsan/lit_tests/mutex_cycle2.c b/compiler-rt/lib/tsan/lit_tests/mutex_cycle2.c new file mode 100644 index 00000000000..cd1006d4760 --- /dev/null +++ b/compiler-rt/lib/tsan/lit_tests/mutex_cycle2.c @@ -0,0 +1,25 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: TSAN_OPTIONS=detect_deadlocks=1 %t 2>&1 | FileCheck %s +#include <pthread.h> + +int main() { + pthread_mutex_t mu1, mu2; + pthread_mutex_init(&mu1, NULL); + pthread_mutex_init(&mu2, NULL); + + // mu1 => mu2 + pthread_mutex_lock(&mu1); + pthread_mutex_lock(&mu2); + pthread_mutex_unlock(&mu2); + pthread_mutex_unlock(&mu1); + + // mu2 => mu1 + pthread_mutex_lock(&mu2); + pthread_mutex_lock(&mu1); + // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock) + pthread_mutex_unlock(&mu1); + pthread_mutex_unlock(&mu2); + + pthread_mutex_destroy(&mu1); + pthread_mutex_destroy(&mu2); +} diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc index a92fd90fd9c..217c2f92855 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc @@ -123,12 +123,12 @@ void InitializeMutex() { #endif } -DeadlockDetector::DeadlockDetector() { +InternalDeadlockDetector::InternalDeadlockDetector() { // Rely on zero initialization because some mutexes can be locked before ctor. } #if TSAN_DEBUG && !TSAN_GO -void DeadlockDetector::Lock(MutexType t) { +void InternalDeadlockDetector::Lock(MutexType t) { // Printf("LOCK %d @%zu\n", t, seq_ + 1); CHECK_GT(t, MutexTypeInvalid); CHECK_LT(t, MutexTypeCount); @@ -155,7 +155,7 @@ void DeadlockDetector::Lock(MutexType t) { } } -void DeadlockDetector::Unlock(MutexType t) { +void InternalDeadlockDetector::Unlock(MutexType t) { // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]); CHECK(locked_[t]); locked_[t] = 0; @@ -210,7 +210,7 @@ Mutex::~Mutex() { void Mutex::Lock() { #if TSAN_DEBUG && !TSAN_GO - cur_thread()->deadlock_detector.Lock(type_); + cur_thread()->internal_deadlock_detector.Lock(type_); #endif uptr cmp = kUnlocked; if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, @@ -235,13 +235,13 @@ void Mutex::Unlock() { (void)prev; DCHECK_NE(prev & kWriteLock, 0); #if TSAN_DEBUG && !TSAN_GO - cur_thread()->deadlock_detector.Unlock(type_); + cur_thread()->internal_deadlock_detector.Unlock(type_); #endif } void Mutex::ReadLock() { #if TSAN_DEBUG && !TSAN_GO - cur_thread()->deadlock_detector.Lock(type_); + cur_thread()->internal_deadlock_detector.Lock(type_); #endif uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); if ((prev & kWriteLock) == 0) @@ -263,7 +263,7 @@ void Mutex::ReadUnlock() { DCHECK_EQ(prev & kWriteLock, 0); DCHECK_GT(prev & ~kWriteLock, 0); #if TSAN_DEBUG && !TSAN_GO - cur_thread()->deadlock_detector.Unlock(type_); + cur_thread()->internal_deadlock_detector.Unlock(type_); #endif } diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutex.h b/compiler-rt/lib/tsan/rtl/tsan_mutex.h index a2b489107a9..4e47d7a31f1 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mutex.h +++ b/compiler-rt/lib/tsan/rtl/tsan_mutex.h @@ -65,9 +65,9 @@ class Mutex { typedef GenericScopedLock<Mutex> Lock; typedef GenericScopedReadLock<Mutex> ReadLock; -class DeadlockDetector { +class InternalDeadlockDetector { public: - DeadlockDetector(); + InternalDeadlockDetector(); void Lock(MutexType t); void Unlock(MutexType t); private: diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index aa8cff60bd6..54d9c704eb1 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -30,6 +30,7 @@ #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_asm.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_deadlock_detector.h" #include "sanitizer_common/sanitizer_libignore.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_thread_registry.h" @@ -449,7 +450,8 @@ struct ThreadState { const uptr tls_size; ThreadContext *tctx; - DeadlockDetector deadlock_detector; + InternalDeadlockDetector internal_deadlock_detector; + __sanitizer::DeadlockDetectorTLS deadlock_detector_tls; bool in_signal_handler; SignalContext *signal_ctx; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc index 62221f298b4..f6c4f858bb0 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include <sanitizer_common/sanitizer_deadlock_detector.h> + #include "tsan_rtl.h" #include "tsan_flags.h" #include "tsan_sync.h" @@ -20,6 +22,14 @@ namespace __tsan { +static __sanitizer::DeadlockDetector<TwoLevelBitVector<> > g_deadlock_detector; + +static void EnsureDeadlockDetectorID(ThreadState *thr, SyncVar *s) { + if (!s->deadlock_detector_id) + s->deadlock_detector_id = + g_deadlock_detector.newNode(reinterpret_cast<uptr>(s)); +} + void MutexCreate(ThreadState *thr, uptr pc, uptr addr, bool rw, bool recursive, bool linker_init) { Context *ctx = CTX(); @@ -35,6 +45,10 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr, s->is_rw = rw; s->is_recursive = recursive; s->is_linker_init = linker_init; + if (common_flags()->detect_deadlocks) { + EnsureDeadlockDetectorID(thr, s); + Printf("MutexCreate: %zx\n", s->deadlock_detector_id); + } s->mtx.Unlock(); } @@ -51,6 +65,10 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr); if (s == 0) return; + if (common_flags()->detect_deadlocks) { + EnsureDeadlockDetectorID(thr, s); + Printf("MutexDestroy: %zx\n", s->deadlock_detector_id); + } if (IsAppMem(addr)) { CHECK(!thr->is_freeing); thr->is_freeing = true; @@ -104,6 +122,15 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) { } s->recursion += rec; thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); + if (common_flags()->detect_deadlocks) { + EnsureDeadlockDetectorID(thr, s); + 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)" + : ""); + } s->mtx.Unlock(); } @@ -140,6 +167,12 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { } } thr->mset.Del(s->GetId(), true); + if (common_flags()->detect_deadlocks) { + EnsureDeadlockDetectorID(thr, s); + Printf("MutexUnlock: %zx\n", s->deadlock_detector_id); + g_deadlock_detector.onUnlock(&thr->deadlock_detector_tls, + s->deadlock_detector_id); + } s->mtx.Unlock(); return rec; } diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/compiler-rt/lib/tsan/rtl/tsan_sync.cc index f8f3c40fab0..6def3c1244b 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_sync.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cc @@ -62,6 +62,7 @@ SyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) { void *mem = internal_alloc(MBlockSync, sizeof(SyncVar)); const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed); SyncVar *res = new(mem) SyncVar(addr, uid); + res->deadlock_detector_id = 0; #ifndef TSAN_GO res->creation_stack_id = CurrentStackId(thr, pc); #endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.h b/compiler-rt/lib/tsan/rtl/tsan_sync.h index 823af543f59..2a90d2d4493 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_sync.h +++ b/compiler-rt/lib/tsan/rtl/tsan_sync.h @@ -61,6 +61,7 @@ struct SyncVar { SyncClock read_clock; // Used for rw mutexes only. u32 creation_stack_id; int owner_tid; // Set only by exclusive owners. + uptr deadlock_detector_id; u64 last_lock; int recursion; bool is_rw; |

