[compiler-rt] r202485 - tsan: refactor deadlock detector

Dmitry Vyukov dvyukov at google.com
Fri Feb 28 02:48:13 PST 2014


Author: dvyukov
Date: Fri Feb 28 04:48:13 2014
New Revision: 202485

URL: http://llvm.org/viewvc/llvm-project?rev=202485&view=rev
Log:
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.


Added:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
Modified:
    compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
    compiler-rt/trunk/lib/tsan/go/buildgo.sh
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h

Modified: compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt Fri Feb 28 04:48:13 2014
@@ -5,6 +5,7 @@ set(SANITIZER_SOURCES
   sanitizer_allocator.cc
   sanitizer_common.cc
   sanitizer_coverage.cc
+  sanitizer_deadlock_detector1.cc
   sanitizer_flags.cc
   sanitizer_libc.cc
   sanitizer_libignore.cc
@@ -52,6 +53,7 @@ set(SANITIZER_HEADERS
   sanitizer_common_interceptors_format.inc
   sanitizer_common_syscalls.inc
   sanitizer_deadlock_detector.h
+  sanitizer_deadlock_detector_interface.h
   sanitizer_flags.h
   sanitizer_internal_defs.h
   sanitizer_lfstack.h

Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc?rev=202485&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc Fri Feb 28 04:48:13 2014
@@ -0,0 +1,141 @@
+//===-- sanitizer_deadlock_detector1.cc -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on NxN adjacency bit matrix.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_deadlock_detector.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+typedef TwoLevelBitVector<> DDBV;  // DeadlockDetector's bit vector.
+
+struct DDPhysicalThread {
+};
+
+struct DDLogicalThread {
+  u64 ctx;
+  DeadlockDetectorTLS<DDBV> dd;
+  DDReport rep;
+};
+
+struct DDetectorImpl : public DDetector {
+  SpinMutex mtx;
+  DeadlockDetector<DDBV> dd;
+
+  DDetectorImpl();
+
+  virtual DDPhysicalThread* CreatePhysicalThread();
+  virtual void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+  virtual DDLogicalThread* CreateLogicalThread(u64 ctx);
+  virtual void DestroyLogicalThread(DDLogicalThread *lt);
+
+  virtual void MutexInit(DDMutex *m, u32 stk, u64 ctx);
+  virtual DDReport *MutexLock(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m, bool writelock, bool trylock);
+  virtual DDReport *MutexUnlock(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m, bool writelock);
+  virtual void MutexDestroy(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m);
+
+  void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
+};
+
+DDetector *DDetector::Create() {
+  void *mem = MmapOrDie(sizeof(DDetectorImpl), "deadlock detector");
+  return new(mem) DDetectorImpl();
+}
+
+DDetectorImpl::DDetectorImpl() {
+  dd.clear();
+}
+
+DDPhysicalThread* DDetectorImpl::CreatePhysicalThread() {
+  return 0;
+}
+
+void DDetectorImpl::DestroyPhysicalThread(DDPhysicalThread *pt) {
+}
+
+DDLogicalThread* DDetectorImpl::CreateLogicalThread(u64 ctx) {
+  DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt));
+  lt->ctx = ctx;
+  lt->dd.clear();
+  return lt;
+}
+
+void DDetectorImpl::DestroyLogicalThread(DDLogicalThread *lt) {
+  lt->~DDLogicalThread();
+  InternalFree(lt);
+}
+
+void DDetectorImpl::MutexInit(DDMutex *m, u32 stk, u64 ctx) {
+  m->id = 0;
+  m->stk = stk;
+  m->ctx = ctx;
+}
+
+void DDetectorImpl::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) {
+  if (!dd.nodeBelongsToCurrentEpoch(m->id))
+    m->id = dd.newNode(reinterpret_cast<uptr>(m));
+  dd.ensureCurrentEpoch(&lt->dd);
+}
+
+DDReport *DDetectorImpl::MutexLock(DDPhysicalThread *pt, DDLogicalThread *lt,
+    DDMutex *m, bool writelock, bool trylock) {
+  SpinMutexLock lk(&mtx);
+  MutexEnsureID(lt, m);
+  CHECK(!dd.isHeld(&lt->dd, m->id));
+  // Printf("T%d MutexLock:   %zx\n", thr->tid, s->deadlock_detector_id);
+  bool has_deadlock = trylock
+      ? dd.onTryLock(&lt->dd, m->id)
+       : dd.onLock(&lt->dd, m->id);
+  DDReport *rep = 0;
+  if (has_deadlock) {
+    uptr path[10];
+    uptr len = dd.findPathToHeldLock(&lt->dd, m->id,
+                                          path, ARRAY_SIZE(path));
+    CHECK_GT(len, 0U);  // Hm.. cycle of 10 locks? I'd like to see that.
+    rep = &lt->rep;
+    rep->n = len;
+    for (uptr i = 0; i < len; i++) {
+      DDMutex *m0 = (DDMutex*)dd.getData(path[i]);
+      DDMutex *m1 = (DDMutex*)dd.getData(path[i < len - 1 ? i + 1 : 0]);
+      rep->loop[i].thr_ctx = 0;  // don't know
+      rep->loop[i].mtx_ctx0 = m0->ctx;
+      rep->loop[i].mtx_ctx1 = m1->ctx;
+      rep->loop[i].stk = m0->stk;
+    }
+  }
+  return rep;
+}
+
+DDReport *DDetectorImpl::MutexUnlock(DDPhysicalThread *pt, DDLogicalThread *lt,
+    DDMutex *m, bool writelock) {
+  // Printf("T%d MutexUnlock: %zx; recursion %d\n", thr->tid,
+  //        s->deadlock_detector_id, s->recursion);
+  dd.onUnlock(&lt->dd, m->id);
+  return 0;
+}
+
+void DDetectorImpl::MutexDestroy(DDPhysicalThread *pt, DDLogicalThread *lt,
+    DDMutex *m) {
+  SpinMutexLock lk(&mtx);
+  if (dd.nodeBelongsToCurrentEpoch(m->id))
+    dd.removeNode(m->id);
+  m->id = 0;
+}
+
+}  // namespace __sanitizer

Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h?rev=202485&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h Fri Feb 28 04:48:13 2014
@@ -0,0 +1,66 @@
+//===-- sanitizer_deadlock_detector_interface.h -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer runtime.
+// Abstract deadlock detector interface.
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+#define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// dd - deadlock detector.
+// lt - logical (user) thread.
+// pt - physical (OS) thread.
+
+struct DDMutex {
+  uptr id;
+  u32  stk;  // creation (or any other) stack that indentifies the mutex
+  u64  ctx;  // user context
+};
+
+struct DDReport {
+  int n;  // number of entries in loop
+  struct {
+    u64 thr_ctx;   // user thread context
+    u64 mtx_ctx0;  // user mutex context, start of the edge
+    u64 mtx_ctx1;  // user mutex context, end of the edge
+    u32 stk;       // stack id for the edge
+  } loop[16];
+};
+
+struct DDPhysicalThread;
+struct DDLogicalThread;
+
+struct DDetector {
+  static DDetector *Create();
+
+  virtual DDPhysicalThread* CreatePhysicalThread() { return 0; }
+  virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {}
+
+  virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; }
+  virtual void DestroyLogicalThread(DDLogicalThread *lt) {}
+
+  virtual void MutexInit(DDMutex *m, u32 stk, u64 ctx) {}
+  virtual DDReport *MutexLock(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m, bool writelock, bool trylock) { return 0; }
+  virtual DDReport *MutexUnlock(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m, bool writelock) { return 0; }
+  virtual void MutexDestroy(DDPhysicalThread *pt, DDLogicalThread *lt,
+      DDMutex *m) {}
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H

Modified: compiler-rt/trunk/lib/tsan/go/buildgo.sh
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/go/buildgo.sh?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/go/buildgo.sh (original)
+++ compiler-rt/trunk/lib/tsan/go/buildgo.sh Fri Feb 28 04:48:13 2014
@@ -17,6 +17,7 @@ SRCS="
 	../rtl/tsan_sync.cc
 	../../sanitizer_common/sanitizer_allocator.cc
 	../../sanitizer_common/sanitizer_common.cc
+	../../sanitizer_common/sanitizer_deadlock_detector1.cc
 	../../sanitizer_common/sanitizer_flags.cc
 	../../sanitizer_common/sanitizer_libc.cc
 	../../sanitizer_common/sanitizer_printf.cc

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Fri Feb 28 04:48:13 2014
@@ -82,9 +82,7 @@ Context::Context()
       CreateThreadContext, kMaxTid, kThreadQuarantineSize))
   , racy_stacks(MBlockRacyStacks)
   , racy_addresses(MBlockRacyAddresses)
-  , fired_suppressions(8)
-  , dd_mtx(MutexTypeDDetector, StatMtxDeadlockDetector) {
-  dd.clear();
+  , fired_suppressions(8) {
 }
 
 // The objects are allocated in TLS, so one may rely on zero-initialization.
@@ -252,6 +250,8 @@ void Initialize(ThreadState *thr) {
   Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
 #endif
   internal_start_thread(&BackgroundThread, 0);
+  if (flags()->detect_deadlocks)
+    ctx->dd = DDetector::Create();
 
   if (ctx->flags.verbosity)
     Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",

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=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Fri Feb 28 04:48:13 2014
@@ -30,7 +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_deadlock_detector_interface.h"
 #include "sanitizer_common/sanitizer_libignore.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
@@ -390,8 +390,6 @@ class Shadow : public FastState {
 
 struct SignalContext;
 
-typedef TwoLevelBitVector<> DDBV;  // DeadlockDetector's bit vector.
-
 struct JmpBuf {
   uptr sp;
   uptr mangled_sp;
@@ -453,7 +451,8 @@ struct ThreadState {
   ThreadContext *tctx;
 
   InternalDeadlockDetector internal_deadlock_detector;
-  __sanitizer::DeadlockDetectorTLS<DDBV> deadlock_detector_tls;
+  DDPhysicalThread *dd_pt;
+  DDLogicalThread *dd_lt;
 
   bool in_signal_handler;
   SignalContext *signal_ctx;
@@ -548,9 +547,7 @@ struct Context {
   Vector<RacyAddress> racy_addresses;
   // Number of fired suppressions may be large enough.
   InternalMmapVector<FiredSuppression> fired_suppressions;
-
-  __sanitizer::DeadlockDetector<DDBV> dd;
-  Mutex dd_mtx;
+  DDetector *dd;
 
   Flags flags;
 
@@ -583,6 +580,7 @@ class ScopedReport {
                        const MutexSet *mset);
   void AddThread(const ThreadContext *tctx);
   void AddMutex(const SyncVar *s);
+  u64 AddMutex(u64 id);
   void AddLocation(uptr addr, uptr size);
   void AddSleep(u32 stack_id);
   void SetCount(int count);
@@ -596,7 +594,7 @@ class ScopedReport {
   // at best it will cause deadlocks on internal mutexes.
   ScopedIgnoreInterceptors ignore_interceptors_;
 
-  void AddMutex(u64 id);
+  void AddDeadMutex(u64 id);
 
   ScopedReport(const ScopedReport&);
   void operator = (const ScopedReport&);

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=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Fri Feb 28 04:48:13 2014
@@ -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
   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
   }
   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 p
     }
   }
   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, 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);
+  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, u
     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
     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
   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

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Fri Feb 28 04:48:13 2014
@@ -181,23 +181,9 @@ void ScopedReport::AddMemoryAccess(uptr
   mop->stack = SymbolizeStack(*stack);
   for (uptr i = 0; i < mset->Size(); i++) {
     MutexSet::Desc d = mset->Get(i);
-    u64 uid = 0;
-    uptr addr = SyncVar::SplitId(d.id, &uid);
-    SyncVar *s = ctx_->synctab.GetIfExistsAndLock(addr, false);
-    // Check that the mutex is still alive.
-    // Another mutex can be created at the same address,
-    // so check uid as well.
-    if (s && s->CheckId(uid)) {
-      ReportMopMutex mtx = {s->uid, d.write};
-      mop->mset.PushBack(mtx);
-      AddMutex(s);
-    } else {
-      ReportMopMutex mtx = {d.id, d.write};
-      mop->mset.PushBack(mtx);
-      AddMutex(d.id);
-    }
-    if (s)
-      s->mtx.ReadUnlock();
+    u64 mid = this->AddMutex(d.id);
+    ReportMopMutex mtx = {mid, d.write};
+    mop->mset.PushBack(mtx);
   }
 }
 
@@ -286,7 +272,26 @@ void ScopedReport::AddMutex(const SyncVa
 #endif
 }
 
-void ScopedReport::AddMutex(u64 id) {
+u64 ScopedReport::AddMutex(u64 id) {
+  u64 uid = 0;
+  u64 mid = id;
+  uptr addr = SyncVar::SplitId(id, &uid);
+  SyncVar *s = ctx_->synctab.GetIfExistsAndLock(addr, false);
+  // Check that the mutex is still alive.
+  // Another mutex can be created at the same address,
+  // so check uid as well.
+  if (s && s->CheckId(uid)) {
+    mid = s->uid;
+    AddMutex(s);
+  } else {
+    AddDeadMutex(id);
+  }
+  if (s)
+    s->mtx.ReadUnlock();
+  return mid;
+}
+
+void ScopedReport::AddDeadMutex(u64 id) {
   for (uptr i = 0; i < rep_->mutexes.Size(); i++) {
     if (rep_->mutexes[i]->id == id)
       return;

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc Fri Feb 28 04:48:13 2014
@@ -83,13 +83,14 @@ struct OnStartedArgs {
 };
 
 void ThreadContext::OnStarted(void *arg) {
+  Context *ctx = CTX();
   OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
   thr = args->thr;
   // RoundUp so that one trace part does not contain events
   // from different threads.
   epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
   epoch1 = (u64)-1;
-  new(thr) ThreadState(CTX(), tid, unique_id,
+  new(thr) ThreadState(ctx, tid, unique_id,
       epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
 #ifndef TSAN_GO
   thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
@@ -106,6 +107,10 @@ void ThreadContext::OnStarted(void *arg)
 #ifndef TSAN_GO
   AllocatorThreadStart(thr);
 #endif
+  if (flags()->detect_deadlocks) {
+    thr->dd_pt = ctx->dd->CreatePhysicalThread();
+    thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
+  }
   thr->fast_synch_epoch = epoch0;
   AcquireImpl(thr, 0, &sync);
   thr->fast_state.SetHistorySize(flags()->history_size);
@@ -122,6 +127,7 @@ void ThreadContext::OnStarted(void *arg)
 }
 
 void ThreadContext::OnFinished() {
+  Context *ctx = CTX();
   if (!detached) {
     thr->fast_state.IncrementEpoch();
     // Can't increment epoch w/o writing to the trace as well.
@@ -130,11 +136,15 @@ void ThreadContext::OnFinished() {
   }
   epoch1 = thr->fast_state.epoch();
 
+  if (flags()->detect_deadlocks) {
+    ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+    ctx->dd->DestroyLogicalThread(thr->dd_lt);
+  }
 #ifndef TSAN_GO
   AllocatorThreadFinish(thr);
 #endif
   thr->~ThreadState();
-  StatAggregate(CTX()->stat, thr->stat);
+  StatAggregate(ctx->stat, thr->stat);
   thr = 0;
 }
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc Fri Feb 28 04:48:13 2014
@@ -58,14 +58,16 @@ SyncVar* SyncTab::GetIfExistsAndLock(upt
 }
 
 SyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) {
+  Context *ctx = CTX();
   StatInc(thr, StatSyncCreated);
   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
+  if (flags()->detect_deadlocks)
+    ctx->dd->MutexInit(&res->dd, res->creation_stack_id, res->GetId());
   return res;
 }
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h?rev=202485&r1=202484&r2=202485&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.h Fri Feb 28 04:48:13 2014
@@ -15,6 +15,7 @@
 
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
 #include "tsan_clock.h"
 #include "tsan_defs.h"
 #include "tsan_mutex.h"
@@ -61,7 +62,6 @@ 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;
@@ -69,6 +69,7 @@ struct SyncVar {
   bool is_broken;
   bool is_linker_init;
   SyncVar *next;  // In SyncTab hashtable.
+  DDMutex dd;
 
   uptr GetMemoryConsumption();
   u64 GetId() const {





More information about the llvm-commits mailing list