summaryrefslogtreecommitdiff
path: root/lib/tsan/rtl/tsan_rtl_mutex.cc
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2014-02-28 10:48:13 +0000
committerDmitry Vyukov <dvyukov@google.com>2014-02-28 10:48:13 +0000
commitff3cbc437a9abb697965659c522c6702be33f144 (patch)
tree8184acc1817be21ae935e5e4c257628632e09336 /lib/tsan/rtl/tsan_rtl_mutex.cc
parentc11c70186e3eac6ddf44be561d7867daf1a085af (diff)
tsan: refactor deadlock detector
Introduce DDetector interface between the tool and the DD itself. It will help to experiment with other DD implementation, as well as reuse DD in other tools. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@202485 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/tsan/rtl/tsan_rtl_mutex.cc')
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc108
1 files changed, 48 insertions, 60 deletions
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index c33328126..fbbd5ee46 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include <sanitizer_common/sanitizer_deadlock_detector.h>
+#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
#include "tsan_rtl.h"
#include "tsan_flags.h"
@@ -22,50 +22,7 @@
namespace __tsan {
-static void EnsureDeadlockDetectorID(Context *ctx, ThreadState *thr,
- SyncVar *s) {
- if (!ctx->dd.nodeBelongsToCurrentEpoch(s->deadlock_detector_id))
- s->deadlock_detector_id = ctx->dd.newNode(reinterpret_cast<uptr>(s));
- ctx->dd.ensureCurrentEpoch(&thr->deadlock_detector_tls);
-}
-
-static void DDUnlock(Context *ctx, ThreadState *thr, SyncVar *s) {
- if (!common_flags()->detect_deadlocks) return;
- if (s->recursion != 0) return;
- // 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);
-}
-
-static void DDLock(Context *ctx, ThreadState *thr, SyncVar *s, uptr pc,
- bool try_lock) {
- if (!common_flags()->detect_deadlocks) return;
- if (s->recursion > 1) return;
- Lock lk(&ctx->dd_mtx);
- EnsureDeadlockDetectorID(ctx, thr, s);
- CHECK(!ctx->dd.isHeld(&thr->deadlock_detector_tls, s->deadlock_detector_id));
- // Printf("T%d MutexLock: %zx\n", thr->tid, 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 ReportDeadlockReport(ThreadState *thr, uptr pc, DDReport *r);
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
bool rw, bool recursive, bool linker_init) {
@@ -98,12 +55,8 @@ 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) {
- Lock lk(&ctx->dd_mtx);
- if (ctx->dd.nodeBelongsToCurrentEpoch(s->deadlock_detector_id))
- ctx->dd.removeNode(s->deadlock_detector_id);
- s->deadlock_detector_id = 0;
- }
+ if (flags()->detect_deadlocks)
+ ctx->dd->MutexDestroy(thr->dd_pt, thr->dd_lt, &s->dd);
if (IsAppMem(addr)) {
CHECK(!thr->is_freeing);
thr->is_freeing = true;
@@ -158,8 +111,12 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
}
s->recursion += rec;
thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
- DDLock(ctx, thr, s, pc, try_lock);
+ DDReport *dd_rep = 0;
+ if (flags()->detect_deadlocks && s->recursion == 1)
+ dd_rep = ctx->dd->MutexLock(thr->dd_pt, thr->dd_lt, &s->dd, true, try_lock);
s->mtx.Unlock();
+ if (dd_rep)
+ ReportDeadlockReport(thr, pc, dd_rep);
}
int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
@@ -196,17 +153,22 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
}
}
thr->mset.Del(s->GetId(), true);
- DDUnlock(ctx, thr, s);
+ DDReport *dd_rep = 0;
+ if (flags()->detect_deadlocks && s->recursion == 0)
+ dd_rep = ctx->dd->MutexUnlock(thr->dd_pt, thr->dd_lt, &s->dd, true);
s->mtx.Unlock();
+ if (dd_rep)
+ ReportDeadlockReport(thr, pc, dd_rep);
return rec;
}
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock) {
+void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
+ Context *ctx = CTX();
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadLock);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
+ SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, false);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
if (s->owner_tid != SyncVar::kInvalidTid) {
@@ -217,16 +179,21 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock) {
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);
+ DDReport *dd_rep = 0;
+ if (flags()->detect_deadlocks && s->recursion == 0)
+ dd_rep = ctx->dd->MutexLock(thr->dd_pt, thr->dd_lt, &s->dd, false, trylock);
s->mtx.ReadUnlock();
+ if (dd_rep)
+ ReportDeadlockReport(thr, pc, dd_rep);
}
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
+ Context *ctx = CTX();
DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadUnlock);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
if (s->owner_tid != SyncVar::kInvalidTid) {
@@ -235,16 +202,21 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
PrintCurrentStack(thr, pc);
}
ReleaseImpl(thr, pc, &s->read_clock);
- DDUnlock(CTX(), thr, s);
+ DDReport *dd_rep = 0;
+ if (flags()->detect_deadlocks && s->recursion == 0)
+ dd_rep = ctx->dd->MutexUnlock(thr->dd_pt, thr->dd_lt, &s->dd, false);
s->mtx.Unlock();
thr->mset.Del(s->GetId(), false);
+ if (dd_rep)
+ ReportDeadlockReport(thr, pc, dd_rep);
}
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
+ Context *ctx = CTX();
DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
- SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
bool write = true;
if (s->owner_tid == SyncVar::kInvalidTid) {
// Seems to be read unlock.
@@ -273,8 +245,12 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
PrintCurrentStack(thr, pc);
}
thr->mset.Del(s->GetId(), write);
- DDUnlock(CTX(), thr, s);
+ DDReport *dd_rep = 0;
+ if (flags()->detect_deadlocks && s->recursion == 0)
+ dd_rep = ctx->dd->MutexUnlock(thr->dd_pt, thr->dd_lt, &s->dd, write);
s->mtx.Unlock();
+ if (dd_rep)
+ ReportDeadlockReport(thr, pc, dd_rep);
}
void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
@@ -394,4 +370,16 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
StatInc(thr, StatSyncRelease);
}
+void ReportDeadlockReport(ThreadState *thr, uptr pc, DDReport *r) {
+ Context *ctx = CTX();
+ ThreadRegistryLock l(ctx->thread_registry);
+ ScopedReport rep(ReportTypeDeadlock);
+ for (int i = 0; i < r->n; i++)
+ rep.AddMutex(r->loop[i].mtx_ctx0);
+ StackTrace trace;
+ trace.ObtainCurrent(thr, pc);
+ rep.AddStack(&trace);
+ OutputReport(ctx, rep);
+}
+
} // namespace __tsan