forked from OSchip/llvm-project
tsan: deadlock detector: print 2 stacks per deadlock edge
llvm-svn: 204149
This commit is contained in:
parent
7fbceb2a3f
commit
b72bc2ec9c
|
|
@ -43,13 +43,15 @@ struct Link {
|
||||||
u32 id;
|
u32 id;
|
||||||
u32 seq;
|
u32 seq;
|
||||||
u32 tid;
|
u32 tid;
|
||||||
u32 stk;
|
u32 stk0;
|
||||||
|
u32 stk1;
|
||||||
|
|
||||||
explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 stk = 0)
|
explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0)
|
||||||
: id(id)
|
: id(id)
|
||||||
, seq(seq)
|
, seq(seq)
|
||||||
, tid(tid)
|
, tid(tid)
|
||||||
, stk(stk) {
|
, stk0(s0)
|
||||||
|
, stk1(s1) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -61,10 +63,15 @@ struct DDPhysicalThread {
|
||||||
Link path[kMaxMutex];
|
Link path[kMaxMutex];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ThreadMutex {
|
||||||
|
u32 id;
|
||||||
|
u32 stk;
|
||||||
|
};
|
||||||
|
|
||||||
struct DDLogicalThread {
|
struct DDLogicalThread {
|
||||||
u64 ctx;
|
u64 ctx;
|
||||||
u32 locked[kMaxNesting];
|
ThreadMutex locked[kMaxNesting];
|
||||||
int nlocked;
|
int nlocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mutex {
|
struct Mutex {
|
||||||
|
|
@ -201,7 +208,9 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
if (m->id == kNoId)
|
if (m->id == kNoId)
|
||||||
m->id = allocateId(cb);
|
m->id = allocateId(cb);
|
||||||
|
|
||||||
lt->locked[lt->nlocked++] = m->id;
|
ThreadMutex *tm = <->locked[lt->nlocked++];
|
||||||
|
tm->id = m->id;
|
||||||
|
tm->stk = cb->Unwind();
|
||||||
if (lt->nlocked == 1) {
|
if (lt->nlocked == 1) {
|
||||||
VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
|
VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
|
||||||
cb->lt->ctx);
|
cb->lt->ctx);
|
||||||
|
|
@ -211,7 +220,8 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
bool added = false;
|
bool added = false;
|
||||||
Mutex *mtx = getMutex(m->id);
|
Mutex *mtx = getMutex(m->id);
|
||||||
for (int i = 0; i < lt->nlocked - 1; i++) {
|
for (int i = 0; i < lt->nlocked - 1; i++) {
|
||||||
u32 id1 = lt->locked[i];
|
u32 id1 = lt->locked[i].id;
|
||||||
|
u32 stk1 = lt->locked[i].stk;
|
||||||
Mutex *mtx1 = getMutex(id1);
|
Mutex *mtx1 = getMutex(id1);
|
||||||
SpinMutexLock l(&mtx1->mtx);
|
SpinMutexLock l(&mtx1->mtx);
|
||||||
if (mtx1->nlink == kMaxLink) {
|
if (mtx1->nlink == kMaxLink) {
|
||||||
|
|
@ -225,7 +235,8 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
if (link->seq != mtx->seq) {
|
if (link->seq != mtx->seq) {
|
||||||
link->seq = mtx->seq;
|
link->seq = mtx->seq;
|
||||||
link->tid = lt->ctx;
|
link->tid = lt->ctx;
|
||||||
link->stk = cb->Unwind();
|
link->stk0 = stk1;
|
||||||
|
link->stk1 = cb->Unwind();
|
||||||
added = true;
|
added = true;
|
||||||
VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
|
VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
|
||||||
cb->lt->ctx, getMutexId(mtx1), m->id);
|
cb->lt->ctx, getMutexId(mtx1), m->id);
|
||||||
|
|
@ -239,7 +250,8 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
link->id = m->id;
|
link->id = m->id;
|
||||||
link->seq = mtx->seq;
|
link->seq = mtx->seq;
|
||||||
link->tid = lt->ctx;
|
link->tid = lt->ctx;
|
||||||
link->stk = cb->Unwind();
|
link->stk0 = stk1;
|
||||||
|
link->stk1 = cb->Unwind();
|
||||||
added = true;
|
added = true;
|
||||||
VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
|
VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
|
||||||
cb->lt->ctx, getMutexId(mtx1), m->id);
|
cb->lt->ctx, getMutexId(mtx1), m->id);
|
||||||
|
|
@ -282,7 +294,9 @@ void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
|
||||||
CHECK_LE(lt->nlocked, kMaxNesting);
|
CHECK_LE(lt->nlocked, kMaxNesting);
|
||||||
if (m->id == kNoId)
|
if (m->id == kNoId)
|
||||||
m->id = allocateId(cb);
|
m->id = allocateId(cb);
|
||||||
lt->locked[lt->nlocked++] = m->id;
|
ThreadMutex *tm = <->locked[lt->nlocked++];
|
||||||
|
tm->id = m->id;
|
||||||
|
tm->stk = cb->Unwind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
|
void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
|
|
@ -301,7 +315,7 @@ void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
CHECK_NE(m->id, kNoId);
|
CHECK_NE(m->id, kNoId);
|
||||||
int last = lt->nlocked - 1;
|
int last = lt->nlocked - 1;
|
||||||
for (int i = last; i >= 0; i--) {
|
for (int i = last; i >= 0; i--) {
|
||||||
if (cb->lt->locked[i] == m->id) {
|
if (cb->lt->locked[i].id == m->id) {
|
||||||
lt->locked[i] = lt->locked[last];
|
lt->locked[i] = lt->locked[last];
|
||||||
lt->nlocked--;
|
lt->nlocked--;
|
||||||
break;
|
break;
|
||||||
|
|
@ -312,14 +326,30 @@ void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||||
void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
|
void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
|
||||||
VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
|
VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
|
||||||
cb->lt->ctx, m);
|
cb->lt->ctx, m);
|
||||||
|
DDLogicalThread *lt = cb->lt;
|
||||||
|
|
||||||
if (m->id == kNoId)
|
if (m->id == kNoId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Remove the mutex from lt->locked if there.
|
||||||
|
int last = lt->nlocked - 1;
|
||||||
|
for (int i = last; i >= 0; i--) {
|
||||||
|
if (lt->locked[i].id == m->id) {
|
||||||
|
lt->locked[i] = lt->locked[last];
|
||||||
|
lt->nlocked--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear and invalidate the mutex descriptor.
|
||||||
{
|
{
|
||||||
Mutex *mtx = getMutex(m->id);
|
Mutex *mtx = getMutex(m->id);
|
||||||
SpinMutexLock l(&mtx->mtx);
|
SpinMutexLock l(&mtx->mtx);
|
||||||
mtx->seq++;
|
mtx->seq++;
|
||||||
mtx->nlink = 0;
|
mtx->nlink = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return id to cache.
|
||||||
{
|
{
|
||||||
SpinMutexLock l(&mtx);
|
SpinMutexLock l(&mtx);
|
||||||
free_id.push_back(m->id);
|
free_id.push_back(m->id);
|
||||||
|
|
@ -377,7 +407,8 @@ void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) {
|
||||||
rep->loop[i].thr_ctx = link->tid;
|
rep->loop[i].thr_ctx = link->tid;
|
||||||
rep->loop[i].mtx_ctx0 = link0->id;
|
rep->loop[i].mtx_ctx0 = link0->id;
|
||||||
rep->loop[i].mtx_ctx1 = link->id;
|
rep->loop[i].mtx_ctx1 = link->id;
|
||||||
rep->loop[i].stk[1] = link->stk;
|
rep->loop[i].stk[0] = link->stk0;
|
||||||
|
rep->loop[i].stk[1] = link->stk1;
|
||||||
}
|
}
|
||||||
pt->report_pending = true;
|
pt->report_pending = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,12 @@ static void ReportDeadlock(Thread *thr, DDReport *rep) {
|
||||||
Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
|
Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
|
||||||
rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
|
rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
|
||||||
PrintStackTrace(thr, rep->loop[i].stk[1]);
|
PrintStackTrace(thr, rep->loop[i].stk[1]);
|
||||||
|
Printf("Mutex %llu was acquired here:\n",
|
||||||
|
rep->loop[i].mtx_ctx0);
|
||||||
|
PrintStackTrace(thr, rep->loop[i].stk[0]);
|
||||||
}
|
}
|
||||||
Printf("==============================\n");
|
Printf("==============================\n");
|
||||||
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
Callback::Callback(Thread *thr)
|
Callback::Callback(Thread *thr)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue