[compiler-rt] r202975 - tsan: implement new version of standalong deadlock detector

Dmitry Vyukov dvyukov at google.com
Wed Mar 5 05:41:22 PST 2014


Author: dvyukov
Date: Wed Mar  5 07:41:21 2014
New Revision: 202975

URL: http://llvm.org/viewvc/llvm-project?rev=202975&view=rev
Log:
tsan: implement new version of standalong deadlock detector
intercept pthread_cond (it is required to properly track state of mutexes)
detect cycles in mutex graph


Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
    compiler-rt/trunk/lib/tsan/dd/CMakeLists.txt
    compiler-rt/trunk/lib/tsan/dd/dd_interceptors.cc
    compiler-rt/trunk/lib/tsan/dd/dd_rtl.cc
    compiler-rt/trunk/lib/tsan/dd/dd_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc

Modified: 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=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector1.cc Wed Mar  5 07:41:21 2014
@@ -30,75 +30,80 @@ struct DDLogicalThread {
   u64 ctx;
   DeadlockDetectorTLS<DDBV> dd;
   DDReport rep;
+  bool report_pending;
 };
 
-struct DDetectorImpl : public DDetector {
+struct DD : public DDetector {
   SpinMutex mtx;
   DeadlockDetector<DDBV> dd;
 
-  DDetectorImpl();
+  DD();
 
-  virtual DDPhysicalThread* CreatePhysicalThread();
-  virtual void DestroyPhysicalThread(DDPhysicalThread *pt);
+  DDPhysicalThread* CreatePhysicalThread();
+  void DestroyPhysicalThread(DDPhysicalThread *pt);
 
-  virtual DDLogicalThread* CreateLogicalThread(u64 ctx);
-  virtual void DestroyLogicalThread(DDLogicalThread *lt);
+  DDLogicalThread* CreateLogicalThread(u64 ctx);
+  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 MutexInit(DDCallback *cb, DDMutex *m);
+  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
+  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+  DDReport *GetReport(DDCallback *cb);
 
   void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
 };
 
 DDetector *DDetector::Create() {
-  void *mem = MmapOrDie(sizeof(DDetectorImpl), "deadlock detector");
-  return new(mem) DDetectorImpl();
+  void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+  return new(mem) DD();
 }
 
-DDetectorImpl::DDetectorImpl() {
+DD::DD() {
   dd.clear();
 }
 
-DDPhysicalThread* DDetectorImpl::CreatePhysicalThread() {
+DDPhysicalThread* DD::CreatePhysicalThread() {
   return 0;
 }
 
-void DDetectorImpl::DestroyPhysicalThread(DDPhysicalThread *pt) {
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
 }
 
-DDLogicalThread* DDetectorImpl::CreateLogicalThread(u64 ctx) {
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
   DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt));
   lt->ctx = ctx;
   lt->dd.clear();
+  lt->report_pending = false;
   return lt;
 }
 
-void DDetectorImpl::DestroyLogicalThread(DDLogicalThread *lt) {
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
   lt->~DDLogicalThread();
   InternalFree(lt);
 }
 
-void DDetectorImpl::MutexInit(DDMutex *m, u32 stk, u64 ctx) {
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
   m->id = 0;
-  m->stk = stk;
-  m->ctx = ctx;
+  m->stk = cb->Unwind();
 }
 
-void DDetectorImpl::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) {
+void DD::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) {
+void DD::MutexBeforeLock(DDCallback *cb,
+    DDMutex *m, bool wlock) {
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) {
+  DDLogicalThread *lt = cb->lt;
   if (dd.onFirstLock(&lt->dd, m->id))
-    return 0;
+    return;
   SpinMutexLock lk(&mtx);
   MutexEnsureID(lt, m);
   CHECK(!dd.isHeld(&lt->dd, m->id));
@@ -106,13 +111,13 @@ DDReport *DDetectorImpl::MutexLock(DDPhy
   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;
+    lt->report_pending = true;
+    DDReport *rep = &lt->rep;
     rep->n = len;
     for (uptr i = 0; i < len; i++) {
       DDMutex *m0 = (DDMutex*)dd.getData(path[i]);
@@ -123,18 +128,15 @@ DDReport *DDetectorImpl::MutexLock(DDPhy
       rep->loop[i].stk = m0->stk;
     }
   }
-  return rep;
 }
 
-DDReport *DDetectorImpl::MutexUnlock(DDPhysicalThread *pt, DDLogicalThread *lt,
-    DDMutex *m, bool writelock) {
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
   // Printf("T%d MutexUnlock: %zx; recursion %d\n", thr->tid,
   //        s->deadlock_detector_id, s->recursion);
-  dd.onUnlock(&lt->dd, m->id);
-  return 0;
+  dd.onUnlock(&cb->lt->dd, m->id);
 }
 
-void DDetectorImpl::MutexDestroy(DDPhysicalThread *pt, DDLogicalThread *lt,
+void DD::MutexDestroy(DDCallback *cb,
     DDMutex *m) {
   if (!m->id) return;
   SpinMutexLock lk(&mtx);
@@ -143,5 +145,12 @@ void DDetectorImpl::MutexDestroy(DDPhysi
   m->id = 0;
 }
 
+DDReport *DD::GetReport(DDCallback *cb) {
+  if (!cb->lt->report_pending)
+    return 0;
+  cb->lt->report_pending = false;
+  return &cb->lt->rep;
+}
+
 }  // namespace __sanitizer
 #endif  // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector2.cc?rev=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector2.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector2.cc Wed Mar  5 07:41:21 2014
@@ -14,125 +14,357 @@
 #include "sanitizer_deadlock_detector_interface.h"
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_placement_new.h"
-//#include "sanitizer_mutex.h"
+#include "sanitizer_mutex.h"
 
 #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
 
 namespace __sanitizer {
 
+const int kMaxMutex = 1024;
+const int kMaxNesting = 64;
+const u32 kNoId = -1;
+const u32 kEndId = -2;
+const int kMaxLink = 8;
+
+struct Id {
+  u32 id;
+  u32 seq;
+
+  explicit Id(u32 id = 0, u32 seq = 0)
+      : id(id)
+      , seq(seq) {
+  }
+};
+
+struct Link {
+  u32 id;
+  u32 seq;
+  u32 tid;
+  u32 stk;
+
+  explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 stk = 0)
+      : id(id)
+      , seq(seq)
+      , tid(tid)
+      , stk(stk) {
+  }
+};
+
 struct DDPhysicalThread {
   DDReport rep;
+  bool report_pending;
+  bool visited[kMaxMutex];
+  Link pending[kMaxMutex];
+  Link path[kMaxMutex];
 };
 
 struct DDLogicalThread {
   u64 ctx;
+  u32 locked[kMaxNesting];
+  int nlocked;
+};
+
+struct Mutex {
+  StaticSpinMutex mtx;
+  u32 seq;
+  int nlink;
+  Link link[kMaxLink];
 };
 
-struct DDetectorImpl : public DDetector {
-  DDetectorImpl();
+struct DD : public DDetector {
+  explicit DD();
+
+  DDPhysicalThread* CreatePhysicalThread();
+  void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+  DDLogicalThread* CreateLogicalThread(u64 ctx);
+  void DestroyLogicalThread(DDLogicalThread *lt);
+
+  void MutexInit(DDCallback *cb, DDMutex *m);
+  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+      bool trylock);
+  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexDestroy(DDCallback *cb, DDMutex *m);
 
-  virtual DDPhysicalThread* CreatePhysicalThread();
-  virtual void DestroyPhysicalThread(DDPhysicalThread *pt);
+  DDReport *GetReport(DDCallback *cb);
 
-  virtual DDLogicalThread* CreateLogicalThread(u64 ctx);
-  virtual void DestroyLogicalThread(DDLogicalThread *lt);
+  void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx);
+  void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath);
 
-  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);
+  SpinMutex mtx;
+  u32 free_id[kMaxMutex];
+  int nfree_id;
+  int id_gen;
+
+  Mutex mutex[kMaxMutex];
 };
 
 DDetector *DDetector::Create() {
-  void *mem = MmapOrDie(sizeof(DDetectorImpl), "deadlock detector");
-  return new(mem) DDetectorImpl();
+  void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+  return new(mem) DD();
 }
 
-DDetectorImpl::DDetectorImpl() {
+DD::DD() {
+  nfree_id = 0;
+  id_gen = 0;
 }
 
-DDPhysicalThread* DDetectorImpl::CreatePhysicalThread() {
-  void *mem = InternalAlloc(sizeof(DDPhysicalThread));
-  DDPhysicalThread *pt = new(mem) DDPhysicalThread();
+DDPhysicalThread* DD::CreatePhysicalThread() {
+  DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread),
+      "deadlock detector (physical thread)");
   return pt;
 }
 
-void DDetectorImpl::DestroyPhysicalThread(DDPhysicalThread *pt) {
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
   pt->~DDPhysicalThread();
   InternalFree(pt);
 }
 
-DDLogicalThread* DDetectorImpl::CreateLogicalThread(u64 ctx) {
-  void *mem = InternalAlloc(sizeof(
-  DDLogicalThread));
-  DDLogicalThread *lt = new(mem) DDLogicalThread();
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+  DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(
+      sizeof(DDLogicalThread));
   lt->ctx = ctx;
+  lt->nlocked = 0;
   return lt;
 }
 
-void DDetectorImpl::DestroyLogicalThread(DDLogicalThread *lt) {
+void DD::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 DD::MutexInit(DDCallback *cb, DDMutex *m) {
+  VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m);
+  m->id = kNoId;
+  m->recursion = 0;
+  atomic_store(&m->owner, 0, memory_order_relaxed);
 }
 
-DDReport *DDetectorImpl::MutexLock(DDPhysicalThread *pt, DDLogicalThread *lt,
-    DDMutex *m, bool writelock, bool trylock) {
-    /*
-  if (dd.onFirstLock(&lt->dd, m->id))
+void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
+  VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, cb->lt->nlocked);
+  DDPhysicalThread *pt = cb->pt;
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n",
+        cb->lt->ctx);
+    return;
+  }
+
+  CHECK_LE(lt->nlocked, kMaxNesting);
+
+  if (m->id == kNoId) {
+    // FIXME(dvyukov): don't allocate id if lt->nlocked == 0
+    SpinMutexLock l(&mtx);
+    if (nfree_id > 0)
+      m->id = free_id[--nfree_id];
+    else
+      m->id = id_gen++;
+    CHECK_LE(id_gen, kMaxMutex);
+    VPrintf(3, "#%llu: DD::MutexBeforeLock assign id %d\n",
+        cb->lt->ctx, m->id);
+  }
+
+  lt->locked[lt->nlocked++] = m->id;
+  if (lt->nlocked == 1) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
+        cb->lt->ctx);
     return 0;
-  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;
-  */
-  return 0;
-}
-
-DDReport *DDetectorImpl::MutexUnlock(DDPhysicalThread *pt, DDLogicalThread *lt,
-    DDMutex *m, bool writelock) {
-  //dd.onUnlock(&lt->dd, m->id);
-  return 0;
+  }
+
+  bool added = false;
+  Mutex *mtx = &mutex[m->id];
+  for (int i = 0; i < lt->nlocked - 1; i++) {
+    u32 id1 = lt->locked[i];
+    Mutex *mtx1 = &mutex[id1];
+    SpinMutexLock l(&mtx1->mtx);
+    if (mtx1->nlink == kMaxLink) {
+      // FIXME(dvyukov): check stale links
+      continue;
+    }
+    int li = 0;
+    for (; li < mtx1->nlink; li++) {
+      Link *link = &mtx1->link[li];
+      if (link->id == m->id) {
+        if (link->seq != mtx->seq) {
+          link->seq = mtx->seq;
+          link->tid = lt->ctx;
+          link->stk = cb->Unwind();
+          added = true;
+          VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+              cb->lt->ctx, mtx1 - mutex, m->id);
+        }
+        break;
+      }
+    }
+    if (li == mtx1->nlink) {
+      // FIXME(dvyukov): check stale links
+      Link *link = &mtx1->link[mtx1->nlink++];
+      link->id = m->id;
+      link->seq = mtx->seq;
+      link->tid = lt->ctx;
+      link->stk = cb->Unwind();
+      added = true;
+      VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+          cb->lt->ctx, mtx1 - mutex, m->id);
+    }
+  }
+
+  if (!added || mtx->nlink == 0) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n",
+        cb->lt->ctx);
+    return;
+  }
+
+  CycleCheck(pt, lt, m);
 }
 
-void DDetectorImpl::MutexDestroy(DDPhysicalThread *pt, DDLogicalThread *lt,
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+    bool trylock) {
+  VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked);
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx);
+    CHECK(wlock);
+    m->recursion++;
+    return;
+  }
+  CHECK_EQ(owner, 0);
+  if (wlock) {
+    VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx);
+    CHECK_EQ(m->recursion, 0);
+    m->recursion = 1;
+    atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed);
+  }
+
+  if (!trylock)
+    return;
+
+  CHECK_LE(lt->nlocked, kMaxNesting);
+  if (m->id == kNoId) {
+    // FIXME(dvyukov): don't allocate id if lt->nlocked == 0
+    SpinMutexLock l(&mtx);
+    if (nfree_id > 0)
+      m->id = free_id[--nfree_id];
+    else
+      m->id = id_gen++;
+    CHECK_LE(id_gen, kMaxMutex);
+    VPrintf(3, "#%llu: DD::MutexAfterLock assign id %d\n", cb->lt->ctx, m->id);
+  }
+
+  lt->locked[lt->nlocked++] = m->id;
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+  VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, cb->lt->nlocked);
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx);
+    if (--m->recursion > 0)
+      return;
+    VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx);
+    atomic_store(&m->owner, 0, memory_order_relaxed);
+  }
+  CHECK_NE(m->id, kNoId);
+  int last = lt->nlocked - 1;
+  for (int i = last; i >= 0; i--) {
+    if (cb->lt->locked[i] == m->id) {
+      lt->locked[i] = lt->locked[last];
+      lt->nlocked--;
+      break;
+    }
+  }
+}
+
+void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
+  VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
+      cb->lt->ctx, m);
+  if (m->id == kNoId)
+    return;
+  {
+    Mutex *mtx = &mutex[m->id];
+    SpinMutexLock l(&mtx->mtx);
+    mtx->seq++;
+    mtx->nlink = 0;
+  }
+  {
+    SpinMutexLock l(&mtx);
+    free_id[nfree_id++] = m->id;
+    m->id = kNoId;
+  }
+}
+
+void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt,
     DDMutex *m) {
-    /*
-  if (!m->id) return;
-  SpinMutexLock lk(&mtx);
-  if (dd.nodeBelongsToCurrentEpoch(m->id))
-    dd.removeNode(m->id);
-  m->id = 0;
-  */
+  // Mutex *mtx = &mutex[m->id];
+  internal_memset(pt->visited, 0, sizeof(pt->visited));
+  int npath = 0;
+  int npending = 0;
+  {
+    Mutex *mtx = &mutex[m->id];
+    SpinMutexLock l(&mtx->mtx);
+    for (int li = 0; li < mtx->nlink; li++)
+      pt->pending[npending++] = mtx->link[li];
+  }
+  while (npending > 0) {
+    Link link = pt->pending[--npending];
+    if (link.id == kEndId) {
+      npath--;
+      continue;
+    }
+    if (pt->visited[link.id])
+      continue;
+    Mutex *mtx1 = &mutex[link.id];
+    SpinMutexLock l(&mtx1->mtx);
+    if (mtx1->seq != link.seq)
+      continue;
+    pt->visited[link.id] = true;
+    if (mtx1->nlink == 0)
+      continue;
+    pt->path[npath++] = link;
+    pt->pending[npending++] = Link(kEndId);
+    if (link.id == m->id)
+      return Report(pt, lt, npath);  // Bingo!
+    for (int li = 0; li < mtx1->nlink; li++) {
+      Link *link1 = &mtx1->link[li];
+      // Mutex *mtx2 = &mutex[link->id];
+      // FIXME(dvyukov): fast seq check
+      // FIXME(dvyukov): fast nlink != 0 check
+      // FIXME(dvyukov): fast pending check?
+      // FIXME(dvyukov): npending can be larger than kMaxMutex
+      pt->pending[npending++] = *link1;
+    }
+  }
+}
+
+void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) {
+  DDReport *rep = &pt->rep;
+  rep->n = npath;
+  for (int i = 0; i < npath; i++) {
+    Link *link = &pt->path[i];
+    Link *link0 = &pt->path[i ? i - 1 : npath - 1];
+    rep->loop[i].thr_ctx = link->tid;
+    rep->loop[i].mtx_ctx0 = link0->id;
+    rep->loop[i].mtx_ctx1 = link->id;
+    rep->loop[i].stk = link->stk;
+  }
+  pt->report_pending = true;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+  if (!cb->lt->report_pending)
+    return 0;
+  cb->lt->report_pending = false;
+  return &cb->lt->rep;
 }
 
 }  // namespace __sanitizer

Modified: 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=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h Wed Mar  5 07:41:21 2014
@@ -16,9 +16,12 @@
 #ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
 #define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
 
-#define SANITIZER_DEADLOCK_DETECTOR_VERSION 1
+#ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION
+# define SANITIZER_DEADLOCK_DETECTOR_VERSION 1
+#endif
 
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_atomic.h"
 
 namespace __sanitizer {
 
@@ -26,10 +29,21 @@ namespace __sanitizer {
 // lt - logical (user) thread.
 // pt - physical (OS) thread.
 
+struct DDPhysicalThread;
+struct DDLogicalThread;
+
 struct DDMutex {
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
   uptr id;
-  u32  stk;  // creation (or any other) stack that indentifies the mutex
-  u64  ctx;  // user context
+  u32  stk;  // creation stack
+  u64  ctx;
+#elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+  u32              id;
+  u32              recursion;
+  atomic_uintptr_t owner;
+#else
+# error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION"
+#endif
 };
 
 struct DDReport {
@@ -42,8 +56,12 @@ struct DDReport {
   } loop[16];
 };
 
-struct DDPhysicalThread;
-struct DDLogicalThread;
+struct DDCallback {
+  DDPhysicalThread *pt;
+  DDLogicalThread  *lt;
+
+  virtual u32 Unwind() { return 0; }
+};
 
 struct DDetector {
   static DDetector *Create();
@@ -54,13 +72,14 @@ struct DDetector {
   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) {}
+  virtual void MutexInit(DDCallback *cb, DDMutex *m) {}
+  virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {}
+  virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+      bool trylock) {}
+  virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {}
+  virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
+
+  virtual DDReport *GetReport(DDCallback *cb) { return 0; }
 };
 
 } // namespace __sanitizer

Modified: compiler-rt/trunk/lib/tsan/dd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/dd/CMakeLists.txt?rev=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/dd/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/tsan/dd/CMakeLists.txt Wed Mar  5 07:41:21 2014
@@ -12,6 +12,7 @@ else()
 endif()
 
 set(DD_DYNAMIC_DEFINITIONS DYNAMIC=1)
+set(DD_COMMON_DEFINITIONS SANITIZER_DEADLOCK_DETECTOR_VERSION=2)
 
 set(DD_SOURCES
   dd_rtl.cc

Modified: compiler-rt/trunk/lib/tsan/dd/dd_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/dd/dd_interceptors.cc?rev=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/dd/dd_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/dd/dd_interceptors.cc Wed Mar  5 07:41:21 2014
@@ -10,6 +10,7 @@
 #include "dd_rtl.h"
 #include "interception/interception.h"
 #include <pthread.h>
+#include <stdlib.h>
 
 using namespace __dsan;
 
@@ -34,21 +35,23 @@ INTERCEPTOR(int, pthread_mutex_destroy,
 
 INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
   InitThread();
-  MutexLock(thr, (uptr)m, true, false);
-  return REAL(pthread_mutex_lock)(m);
+  MutexBeforeLock(thr, (uptr)m, true);
+  int res = REAL(pthread_mutex_lock)(m);
+  MutexAfterLock(thr, (uptr)m, true, false);
+  return res;
 }
 
 INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
   InitThread();
   int res = REAL(pthread_mutex_trylock)(m);
   if (res == 0)
-    MutexLock(thr, (uptr)m, true, true);
+    MutexAfterLock(thr, (uptr)m, true, true);
   return res;
 }
 
 INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
   InitThread();
-  MutexUnlock(thr, (uptr)m, true);
+  MutexBeforeUnlock(thr, (uptr)m, true);
   return REAL(pthread_mutex_unlock)(m);
 }
 
@@ -61,21 +64,23 @@ INTERCEPTOR(int, pthread_spin_destroy, p
 
 INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) {
   InitThread();
-  MutexLock(thr, (uptr)m, true, false);
-  return REAL(pthread_spin_lock)(m);
+  MutexBeforeLock(thr, (uptr)m, true);
+  int res = REAL(pthread_spin_lock)(m);
+  MutexAfterLock(thr, (uptr)m, true, false);
+  return res;
 }
 
 INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) {
   InitThread();
   int res = REAL(pthread_spin_trylock)(m);
   if (res == 0)
-    MutexLock(thr, (uptr)m, true, true);
+    MutexAfterLock(thr, (uptr)m, true, true);
   return res;
 }
 
 INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) {
   InitThread();
-  MutexUnlock(thr, (uptr)m, true);
+  MutexBeforeUnlock(thr, (uptr)m, true);
   return REAL(pthread_spin_unlock)(m);
 }
 
@@ -87,15 +92,17 @@ INTERCEPTOR(int, pthread_rwlock_destroy,
 
 INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) {
   InitThread();
-  MutexLock(thr, (uptr)m, false, false);
-  return REAL(pthread_rwlock_rdlock)(m);
+  MutexBeforeLock(thr, (uptr)m, false);
+  int res = REAL(pthread_rwlock_rdlock)(m);
+  MutexAfterLock(thr, (uptr)m, false, false);
+  return res;
 }
 
 INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) {
   InitThread();
   int res = REAL(pthread_rwlock_tryrdlock)(m);
   if (res == 0)
-    MutexLock(thr, (uptr)m, false, true);
+    MutexAfterLock(thr, (uptr)m, false, true);
   return res;
 }
 
@@ -104,21 +111,23 @@ INTERCEPTOR(int, pthread_rwlock_timedrdl
   InitThread();
   int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
   if (res == 0)
-    MutexLock(thr, (uptr)m, false, true);
+    MutexAfterLock(thr, (uptr)m, false, true);
   return res;
 }
 
 INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) {
   InitThread();
-  MutexLock(thr, (uptr)m, true, false);
-  return REAL(pthread_rwlock_wrlock)(m);
+  MutexBeforeLock(thr, (uptr)m, true);
+  int res = REAL(pthread_rwlock_wrlock)(m);
+  MutexAfterLock(thr, (uptr)m, true, false);
+  return res;
 }
 
 INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) {
   InitThread();
   int res = REAL(pthread_rwlock_trywrlock)(m);
   if (res == 0)
-    MutexLock(thr, (uptr)m, true, true);
+    MutexAfterLock(thr, (uptr)m, true, true);
   return res;
 }
 
@@ -127,16 +136,79 @@ INTERCEPTOR(int, pthread_rwlock_timedwrl
   InitThread();
   int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
   if (res == 0)
-    MutexLock(thr, (uptr)m, true, true);
+    MutexAfterLock(thr, (uptr)m, true, true);
   return res;
 }
 
 INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) {
   InitThread();
-  MutexUnlock(thr, (uptr)m, true);  // note: not necessary write unlock
+  MutexBeforeUnlock(thr, (uptr)m, true);  // note: not necessary write unlock
   return REAL(pthread_rwlock_unlock)(m);
 }
 
+static pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) {
+  atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+  uptr cond = atomic_load(p, memory_order_acquire);
+  if (!force && cond != 0)
+    return (pthread_cond_t*)cond;
+  void *newcond = malloc(sizeof(pthread_cond_t));
+  internal_memset(newcond, 0, sizeof(pthread_cond_t));
+  if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+      memory_order_acq_rel))
+    return (pthread_cond_t*)newcond;
+  free(newcond);
+  return (pthread_cond_t*)cond;
+}
+
+INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c,
+    const pthread_condattr_t *a) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c, true);
+  return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c);
+  MutexBeforeUnlock(thr, (uptr)m, true);
+  MutexBeforeLock(thr, (uptr)m, true);
+  int res = REAL(pthread_cond_wait)(cond, m);
+  MutexAfterLock(thr, (uptr)m, true, false);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m,
+    const timespec *abstime) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c);
+  MutexBeforeUnlock(thr, (uptr)m, true);
+  MutexBeforeLock(thr, (uptr)m, true);
+  int res = REAL(pthread_cond_timedwait)(cond, m, abstime);
+  MutexAfterLock(thr, (uptr)m, true, false);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c);
+  return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c);
+  return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) {
+  InitThread();
+  pthread_cond_t *cond = init_cond(c);
+  int res = REAL(pthread_cond_destroy)(cond);
+  free(cond);
+  atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+  return res;
+}
+
 namespace __dsan {
 
 void InitializeInterceptors() {
@@ -158,6 +230,13 @@ void InitializeInterceptors() {
   INTERCEPT_FUNCTION(pthread_rwlock_trywrlock);
   INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock);
   INTERCEPT_FUNCTION(pthread_rwlock_unlock);
+
+  INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
+  INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
+  INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+  INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
+  INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+  INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
 }
 
 }  // namespace __dsan

Modified: compiler-rt/trunk/lib/tsan/dd/dd_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/dd/dd_rtl.cc?rev=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/dd/dd_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/dd/dd_rtl.cc Wed Mar  5 07:41:21 2014
@@ -18,32 +18,11 @@ namespace __dsan {
 
 static Context *ctx;
 
-void Initialize() {
-  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
-  ctx = new(ctx_mem) Context();
-
-  InitializeInterceptors();
-  //common_flags()->allow_addr2line = true;
-  common_flags()->symbolize = true;
-  ctx->dd = DDetector::Create();
-}
-
-void ThreadInit(Thread *thr) {
-  thr->dd_pt = ctx->dd->CreatePhysicalThread();
-  thr->dd_lt = ctx->dd->CreateLogicalThread(0);
-}
-
-void ThreadDestroy(Thread *thr) {
-  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
-  ctx->dd->DestroyLogicalThread(thr->dd_lt);
-}
-
-static u32 CurrentStackTrace(Thread *thr) {
+static u32 CurrentStackTrace(Thread *thr, uptr skip) {
   StackTrace trace;
   thr->ignore_interceptors = true;
   trace.Unwind(1000, 0, 0, 0, 0, 0, false);
   thr->ignore_interceptors = false;
-  const uptr skip = 4;
   if (trace.size <= skip)
     return 0;
   return StackDepotPut(trace.trace + skip, trace.size - skip);
@@ -58,45 +37,96 @@ static void PrintStackTrace(Thread *thr,
 }
 
 static void ReportDeadlock(Thread *thr, DDReport *rep) {
+  if (rep == 0)
+    return;
   Printf("==============================\n");
-  Printf("DEADLOCK\n");
-  PrintStackTrace(thr, CurrentStackTrace(thr));
+  Printf("WARNING: lock-order-inversion (potential deadlock)\n");
   for (int i = 0; i < rep->n; i++) {
-    Printf("Mutex %llu created at:\n", rep->loop[i].mtx_ctx0);
+    Printf("Thread %d locks mutex %llu under mutex %llu:\n",
+      rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
     PrintStackTrace(thr, rep->loop[i].stk);
   }
   Printf("==============================\n");
 }
 
-void MutexLock(Thread *thr, uptr m, bool writelock, bool trylock) {
+Callback::Callback(Thread *thr)
+    : thr(thr) {
+  lt = thr->dd_lt;
+  pt = thr->dd_pt;
+}
+
+u32 Callback::Unwind() {
+  return CurrentStackTrace(thr, 3);
+}
+
+void Initialize() {
+  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
+  ctx = new(ctx_mem) Context();
+
+  InitializeInterceptors();
+  ParseCommonFlagsFromString(flags(), GetEnv("DSAN_OPTIONS"));
+  //common_flags()->allow_addr2line = true;
+  common_flags()->symbolize = true;
+  ctx->dd = DDetector::Create();
+}
+
+void ThreadInit(Thread *thr) {
+  static atomic_uintptr_t id_gen;
+  uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
+  thr->dd_pt = ctx->dd->CreatePhysicalThread();
+  thr->dd_lt = ctx->dd->CreateLogicalThread(id);
+}
+
+void ThreadDestroy(Thread *thr) {
+  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+  ctx->dd->DestroyLogicalThread(thr->dd_lt);
+}
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
   if (thr->ignore_interceptors)
     return;
-  DDReport *rep = 0;
+  Callback cb(thr);
   {
     MutexHashMap::Handle h(&ctx->mutex_map, m);
     if (h.created())
-      ctx->dd->MutexInit(&h->dd, CurrentStackTrace(thr), m);
-    rep = ctx->dd->MutexLock(thr->dd_pt, thr->dd_lt, &h->dd,
-                             writelock, trylock);
+      ctx->dd->MutexInit(&cb, &h->dd);
+    ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
   }
-  if (rep)
-    ReportDeadlock(thr, rep);
+  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
 }
 
-void MutexUnlock(Thread *thr, uptr m, bool writelock) {
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
   if (thr->ignore_interceptors)
     return;
-  MutexHashMap::Handle h(&ctx->mutex_map, m);
-  ctx->dd->MutexUnlock(thr->dd_pt, thr->dd_lt, &h->dd, writelock);
+  Callback cb(thr);
+  {
+    MutexHashMap::Handle h(&ctx->mutex_map, m);
+    if (h.created())
+      ctx->dd->MutexInit(&cb, &h->dd);
+    ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
+  }
+  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
+  if (thr->ignore_interceptors)
+    return;
+  Callback cb(thr);
+  {
+    MutexHashMap::Handle h(&ctx->mutex_map, m);
+    ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
+  }
+  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
 }
 
 void MutexDestroy(Thread *thr, uptr m) {
   if (thr->ignore_interceptors)
     return;
+  Callback cb(thr);
   MutexHashMap::Handle h(&ctx->mutex_map, m, true);
   if (!h.exists())
     return;
-  ctx->dd->MutexDestroy(thr->dd_pt, thr->dd_lt, &h->dd);
+  ctx->dd->MutexDestroy(&cb, &h->dd);
 }
 
 }  // namespace __dsan

Modified: compiler-rt/trunk/lib/tsan/dd/dd_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/dd/dd_rtl.h?rev=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/dd/dd_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/dd/dd_rtl.h Wed Mar  5 07:41:21 2014
@@ -11,6 +11,7 @@
 
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_addrhashmap.h"
 #include "sanitizer_common/sanitizer_mutex.h"
@@ -28,6 +29,13 @@ struct Thread {
   bool ignore_interceptors;
 };
 
+struct Callback : DDCallback {
+  Thread *thr;
+
+  Callback(Thread *thr);
+  virtual u32 Unwind();
+};
+
 typedef AddrHashMap<Mutex, 1000003> MutexHashMap;
 
 struct Context {
@@ -36,14 +44,19 @@ struct Context {
   MutexHashMap mutex_map;
 };
 
+inline CommonFlags* flags() {
+  return common_flags();
+}
+
 void Initialize();
 void InitializeInterceptors();
 
 void ThreadInit(Thread *thr);
 void ThreadDestroy(Thread *thr);
 
-void MutexLock(Thread *thr, uptr m, bool writelock, bool trylock);
-void MutexUnlock(Thread *thr, uptr m, bool writelock);
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock);
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock);
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock);
 void MutexDestroy(Thread *thr, uptr m);
 
 }  // namespace __dsan

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=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Wed Mar  5 07:41:21 2014
@@ -22,7 +22,33 @@
 
 namespace __tsan {
 
-void ReportDeadlockReport(ThreadState *thr, uptr pc, DDReport *r);
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
+
+struct Callback : DDCallback {
+  ThreadState *thr;
+  uptr pc;
+
+  Callback(ThreadState *thr, uptr pc)
+      : thr(thr)
+      , pc(pc) {
+    DDCallback::pt = thr->dd_pt;
+    DDCallback::lt = thr->dd_lt;
+  }
+
+  virtual u32 Unwind() {
+#ifdef TSAN_GO
+    return 0;
+#else
+    return CurrentStackId(thr, pc);
+#endif
+  }
+};
+
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
+  Callback cb(thr, pc);
+  CTX()->dd->MutexInit(&cb, &s->dd);
+  s->dd.ctx = s->GetId();
+}
 
 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
                  bool rw, bool recursive, bool linker_init) {
@@ -55,8 +81,10 @@ void MutexDestroy(ThreadState *thr, uptr
   SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
   if (s == 0)
     return;
-  if (flags()->detect_deadlocks)
-    ctx->dd->MutexDestroy(thr->dd_pt, thr->dd_lt, &s->dd);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexDestroy(&cb, &s->dd);
+  }
   if (IsAppMem(addr)) {
     CHECK(!thr->is_freeing);
     thr->is_freeing = true;
@@ -111,12 +139,16 @@ void MutexLock(ThreadState *thr, uptr pc
   }
   s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
-  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);
+  if (flags()->detect_deadlocks && s->recursion == 1) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
+    ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
+  }
   s->mtx.Unlock();
-  if (dd_rep)
-    ReportDeadlockReport(thr, pc, dd_rep);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+  }
 }
 
 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
@@ -153,12 +185,15 @@ int MutexUnlock(ThreadState *thr, uptr p
     }
   }
   thr->mset.Del(s->GetId(), true);
-  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);
+  if (flags()->detect_deadlocks && s->recursion == 0) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
+  }
   s->mtx.Unlock();
-  if (dd_rep)
-    ReportDeadlockReport(thr, pc, dd_rep);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+  }
   return rec;
 }
 
@@ -179,12 +214,16 @@ 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());
-  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);
+  if (flags()->detect_deadlocks && s->recursion == 0) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
+    ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
+  }
   s->mtx.ReadUnlock();
-  if (dd_rep)
-    ReportDeadlockReport(thr, pc, dd_rep);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+  }
 }
 
 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
@@ -202,13 +241,16 @@ void MutexReadUnlock(ThreadState *thr, u
     PrintCurrentStack(thr, pc);
   }
   ReleaseImpl(thr, pc, &s->read_clock);
-  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);
+  if (flags()->detect_deadlocks && s->recursion == 0) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
+  }
   s->mtx.Unlock();
   thr->mset.Del(s->GetId(), false);
-  if (dd_rep)
-    ReportDeadlockReport(thr, pc, dd_rep);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+  }
 }
 
 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
@@ -245,12 +287,15 @@ void MutexReadOrWriteUnlock(ThreadState
     PrintCurrentStack(thr, pc);
   }
   thr->mset.Del(s->GetId(), write);
-  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);
+  if (flags()->detect_deadlocks && s->recursion == 0) {
+    Callback cb(thr, pc);
+    ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
+  }
   s->mtx.Unlock();
-  if (dd_rep)
-    ReportDeadlockReport(thr, pc, dd_rep);
+  if (flags()->detect_deadlocks) {
+    Callback cb(thr, pc);
+    ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+  }
 }
 
 void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
@@ -370,7 +415,9 @@ void AcquireReleaseImpl(ThreadState *thr
   StatInc(thr, StatSyncRelease);
 }
 
-void ReportDeadlockReport(ThreadState *thr, uptr pc, DDReport *r) {
+void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
+  if (r == 0)
+    return;
   Context *ctx = CTX();
   ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(ReportTypeDeadlock);

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=202975&r1=202974&r2=202975&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_sync.cc Wed Mar  5 07:41:21 2014
@@ -17,6 +17,8 @@
 
 namespace __tsan {
 
+void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);
+
 SyncVar::SyncVar(uptr addr, u64 uid)
   : mtx(MutexTypeSyncVar, StatMtxSyncVar)
   , addr(addr)
@@ -58,7 +60,6 @@ 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);
@@ -67,7 +68,7 @@ SyncVar* SyncTab::Create(ThreadState *th
   res->creation_stack_id = CurrentStackId(thr, pc);
 #endif
   if (flags()->detect_deadlocks)
-    ctx->dd->MutexInit(&res->dd, res->creation_stack_id, res->GetId());
+    DDMutexInit(thr, pc, res);
   return res;
 }
 





More information about the llvm-commits mailing list