forked from OSchip/llvm-project
[sanitizer] in bitset-based deadlock detector collect edge's stack trace when an edge is added to the graph (in following CLs these stack traces will be added to the report)
llvm-svn: 203902
This commit is contained in:
parent
74af50134b
commit
c067864b6f
|
@ -47,12 +47,16 @@ class BVGraph {
|
|||
}
|
||||
|
||||
// Returns true if at least one new edge was added.
|
||||
bool addEdges(const BV &from, uptr to) {
|
||||
bool res = false;
|
||||
uptr addEdges(const BV &from, uptr to, uptr added_edges[],
|
||||
uptr max_added_edges) {
|
||||
uptr res = 0;
|
||||
t1.copyFrom(from);
|
||||
while (!t1.empty())
|
||||
if (v[t1.getAndClearFirstOne()].setBit(to))
|
||||
res = true;
|
||||
while (!t1.empty()) {
|
||||
uptr node = t1.getAndClearFirstOne();
|
||||
if (v[node].setBit(to))
|
||||
if (res < max_added_edges)
|
||||
added_edges[res++] = node;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ class DeadlockDetector {
|
|||
available_nodes_.clear();
|
||||
recycled_nodes_.clear();
|
||||
g_.clear();
|
||||
n_edges_ = 0;
|
||||
}
|
||||
|
||||
// Allocate new deadlock detector node.
|
||||
|
@ -164,21 +165,49 @@ class DeadlockDetector {
|
|||
return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_));
|
||||
}
|
||||
|
||||
// Returns true if a new edge has been added to the graph.
|
||||
// Should be called before after the lock is acquired.
|
||||
bool onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
|
||||
// Add cur_node to the set of locks held currently by dtls.
|
||||
void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
|
||||
ensureCurrentEpoch(dtls);
|
||||
uptr cur_idx = nodeToIndex(cur_node);
|
||||
g_.addEdges(dtls->getLocks(current_epoch_), cur_idx);
|
||||
return dtls->addLock(cur_idx, current_epoch_);
|
||||
dtls->addLock(cur_idx, current_epoch_);
|
||||
}
|
||||
|
||||
// Adds edges from currently held locks to cur_node,
|
||||
// returns the number of added edges, and puts the sources of added edges
|
||||
// into added_edges[].
|
||||
// Should be called before onLockAfter.
|
||||
uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk) {
|
||||
ensureCurrentEpoch(dtls);
|
||||
uptr cur_idx = nodeToIndex(cur_node);
|
||||
uptr added_edges[40];
|
||||
uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx,
|
||||
added_edges, ARRAY_SIZE(added_edges));
|
||||
for (uptr i = 0; i < n_added_edges; i++) {
|
||||
if (n_edges_ < ARRAY_SIZE(edges_))
|
||||
edges_[n_edges_++] = Edge((u16)added_edges[i], (u16)cur_idx, stk);
|
||||
// Printf("Edge [%zd]: %u %zd=>%zd\n", i, stk, added_edges[i], cur_idx);
|
||||
}
|
||||
return n_added_edges;
|
||||
}
|
||||
|
||||
u32 findEdge(uptr from_node, uptr to_node) {
|
||||
uptr from_idx = nodeToIndex(from_node);
|
||||
uptr to_idx = nodeToIndex(to_node);
|
||||
for (uptr i = 0; i < n_edges_; i++) {
|
||||
if (edges_[i].from == from_idx && edges_[i].to == to_idx)
|
||||
return edges_[i].stk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test-only function. Handles the before/after lock events,
|
||||
// returns true if there is a cycle.
|
||||
bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
|
||||
ensureCurrentEpoch(dtls);
|
||||
bool is_reachable = onLockBefore(dtls, cur_node);
|
||||
return onLockAfter(dtls, cur_node) && is_reachable;
|
||||
bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node);
|
||||
addEdges(dtls, cur_node, 0);
|
||||
onLockAfter(dtls, cur_node);
|
||||
return is_reachable;
|
||||
}
|
||||
|
||||
// Handles the try_lock event, returns false.
|
||||
|
@ -276,12 +305,23 @@ class DeadlockDetector {
|
|||
return indexToNode(idx);
|
||||
}
|
||||
|
||||
struct Edge {
|
||||
u16 from;
|
||||
u16 to;
|
||||
u32 stk;
|
||||
// FIXME: replace with initializer list once the tests are built as c++11.
|
||||
Edge(u16 f, u16 t, u32 s) : from(f), to(t), stk(s) {}
|
||||
Edge() {}
|
||||
};
|
||||
|
||||
uptr current_epoch_;
|
||||
BV available_nodes_;
|
||||
BV recycled_nodes_;
|
||||
BV tmp_bv_;
|
||||
BVGraph<BV> g_;
|
||||
uptr data_[BV::kSize];
|
||||
Edge edges_[BV::kSize * 32];
|
||||
uptr n_edges_;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -112,8 +112,12 @@ void DD::MutexBeforeLock(DDCallback *cb,
|
|||
DDReport *rep = <->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]);
|
||||
uptr from = path[i];
|
||||
uptr to = path[(i + 1) % len];
|
||||
DDMutex *m0 = (DDMutex*)dd.getData(from);
|
||||
DDMutex *m1 = (DDMutex*)dd.getData(to);
|
||||
|
||||
Printf("Edge: %zd=>%zd: %u\n", from, to, dd.findEdge(from, to));
|
||||
rep->loop[i].thr_ctx = 0; // don't know
|
||||
rep->loop[i].mtx_ctx0 = m0->ctx;
|
||||
rep->loop[i].mtx_ctx1 = m1->ctx;
|
||||
|
@ -131,11 +135,9 @@ void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) {
|
|||
MutexEnsureID(lt, m);
|
||||
if (wlock) // Only a recursive rlock may be held.
|
||||
CHECK(!dd.isHeld(<->dd, m->id));
|
||||
bool edge_added =
|
||||
trylock ? dd.onTryLock(<->dd, m->id) : dd.onLockAfter(<->dd, m->id);
|
||||
if (edge_added) {
|
||||
// Printf("Edge added\n");
|
||||
}
|
||||
if (!trylock)
|
||||
dd.addEdges(<->dd, m->id, cb->Unwind());
|
||||
dd.onLockAfter(<->dd, m->id);
|
||||
}
|
||||
|
||||
void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
|
||||
|
|
|
@ -301,3 +301,33 @@ TEST(BVGraph, ShortestPath) {
|
|||
ShortestPath<BV3>();
|
||||
ShortestPath<BV4>();
|
||||
}
|
||||
|
||||
template <class BV>
|
||||
void RunAddEdgesTest() {
|
||||
BVGraph<BV> g;
|
||||
BV from;
|
||||
const int kMaxEdges = 10;
|
||||
uptr added_edges[kMaxEdges];
|
||||
g.clear();
|
||||
from.clear();
|
||||
EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
|
||||
EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
|
||||
from.setBit(0);
|
||||
EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
|
||||
EXPECT_EQ(0U, added_edges[0]);
|
||||
EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
|
||||
|
||||
from.clear();
|
||||
from.setBit(1);
|
||||
EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
|
||||
EXPECT_EQ(1U, added_edges[0]);
|
||||
from.setBit(2);
|
||||
from.setBit(3);
|
||||
EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
|
||||
EXPECT_EQ(2U, added_edges[0]);
|
||||
EXPECT_EQ(3U, added_edges[1]);
|
||||
}
|
||||
|
||||
TEST(BVGraph, AddEdgesTest) {
|
||||
RunAddEdgesTest<BV2>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue