summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/tsan
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2014-02-14 12:20:42 +0000
committerKostya Serebryany <kcc@google.com>2014-02-14 12:20:42 +0000
commita63632a5c6acd6e8865cb0ffc060be1321db7298 (patch)
tree69957e8d6f0c9ee22ad72e2284c123d22fbba9b5 /compiler-rt/lib/tsan
parent127e93e4dcd06d6b965f66ae8eeab6ddc651b759 (diff)
downloadbcm5719-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.c25
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_mutex.cc14
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_mutex.h4
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h4
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc33
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_sync.cc1
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_sync.h1
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;
OpenPOWER on IntegriCloud