[sanitizer] do not acquire a global mutex in deadlock detector when dealing with Unlock (it is essentially a thread-local operation)
llvm-svn: 202401
This commit is contained in:
parent
a12923e265
commit
2ff42d98fa
|
@ -48,16 +48,17 @@ class DeadlockDetectorTLS {
|
||||||
epoch_ = current_epoch;
|
epoch_ = current_epoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr getEpoch() const { return epoch_; }
|
||||||
|
|
||||||
void addLock(uptr lock_id, uptr current_epoch) {
|
void addLock(uptr lock_id, uptr current_epoch) {
|
||||||
// Printf("addLock: %zx %zx\n", lock_id, current_epoch);
|
// Printf("addLock: %zx %zx\n", lock_id, current_epoch);
|
||||||
CHECK_EQ(epoch_, current_epoch);
|
CHECK_EQ(epoch_, current_epoch);
|
||||||
CHECK(bv_.setBit(lock_id));
|
CHECK(bv_.setBit(lock_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeLock(uptr lock_id, uptr current_epoch) {
|
void removeLock(uptr lock_id) {
|
||||||
// Printf("remLock: %zx %zx\n", lock_id, current_epoch);
|
// Printf("remLock: %zx %zx\n", lock_id, current_epoch);
|
||||||
CHECK_EQ(epoch_, current_epoch);
|
CHECK(bv_.clearBit(lock_id));
|
||||||
bv_.clearBit(lock_id); // May already be cleared due to epoch update.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BV &getLocks(uptr current_epoch) const {
|
const BV &getLocks(uptr current_epoch) const {
|
||||||
|
@ -75,7 +76,8 @@ class DeadlockDetectorTLS {
|
||||||
// and one DeadlockDetectorTLS object per evey thread.
|
// and one DeadlockDetectorTLS object per evey thread.
|
||||||
// This class is not thread safe, all concurrent accesses should be guarded
|
// This class is not thread safe, all concurrent accesses should be guarded
|
||||||
// by an external lock.
|
// by an external lock.
|
||||||
// Not thread-safe, all accesses should be protected by an external lock.
|
// Most of the methods of this class are not thread-safe (i.e. should
|
||||||
|
// be protected by an external lock) unless explicitly told otherwise.
|
||||||
template <class BV>
|
template <class BV>
|
||||||
class DeadlockDetector {
|
class DeadlockDetector {
|
||||||
public:
|
public:
|
||||||
|
@ -133,7 +135,7 @@ class DeadlockDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles the lock event, returns true if there is a cycle.
|
// Handles the lock event, returns true if there is a cycle.
|
||||||
// FIXME: handle RW locks, recusive locks, etc.
|
// FIXME: handle RW locks, recursive locks, etc.
|
||||||
bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
|
bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
|
||||||
ensureCurrentEpoch(dtls);
|
ensureCurrentEpoch(dtls);
|
||||||
uptr cur_idx = nodeToIndex(cur_node);
|
uptr cur_idx = nodeToIndex(cur_node);
|
||||||
|
@ -171,10 +173,11 @@ class DeadlockDetector {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the unlock event.
|
// Handle the unlock event. This operation is thread-safe
|
||||||
|
// as it only touches the dtls.
|
||||||
void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
|
void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
|
||||||
ensureCurrentEpoch(dtls);
|
if (dtls->getEpoch() == nodeToEpoch(node))
|
||||||
dtls->removeLock(nodeToIndex(node), current_epoch_);
|
dtls->removeLock(nodeToIndexUnchecked(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
|
bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
|
||||||
|
@ -202,7 +205,7 @@ class DeadlockDetector {
|
||||||
|
|
||||||
void check_node(uptr node) const {
|
void check_node(uptr node) const {
|
||||||
CHECK_GE(node, size());
|
CHECK_GE(node, size());
|
||||||
CHECK_EQ(current_epoch_, node / size() * size());
|
CHECK_EQ(current_epoch_, nodeToEpoch(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr indexToNode(uptr idx) const {
|
uptr indexToNode(uptr idx) const {
|
||||||
|
@ -210,11 +213,15 @@ class DeadlockDetector {
|
||||||
return idx + current_epoch_;
|
return idx + current_epoch_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
|
||||||
|
|
||||||
uptr nodeToIndex(uptr node) const {
|
uptr nodeToIndex(uptr node) const {
|
||||||
check_node(node);
|
check_node(node);
|
||||||
return node % size();
|
return nodeToIndexUnchecked(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
|
||||||
|
|
||||||
uptr getAvailableNode(uptr data) {
|
uptr getAvailableNode(uptr data) {
|
||||||
uptr idx = available_nodes_.getAndClearFirstOne();
|
uptr idx = available_nodes_.getAndClearFirstOne();
|
||||||
data_[idx] = data;
|
data_[idx] = data;
|
||||||
|
|
|
@ -269,9 +269,8 @@ void RunMultipleEpochsTest() {
|
||||||
EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
|
EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
|
||||||
|
|
||||||
// Can not handle the locks from the previous epoch.
|
// Can not handle the locks from the previous epoch.
|
||||||
// The user should update the lock id.
|
// The caller should update the lock id.
|
||||||
EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
|
EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
|
||||||
EXPECT_DEATH(d.onUnlock(&dtls, l1), "CHECK failed.*current_epoch_");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeadlockDetector, MultipleEpochsTest) {
|
TEST(DeadlockDetector, MultipleEpochsTest) {
|
||||||
|
|
|
@ -32,8 +32,6 @@ static void EnsureDeadlockDetectorID(Context *ctx, ThreadState *thr,
|
||||||
static void DDUnlock(Context *ctx, ThreadState *thr, SyncVar *s) {
|
static void DDUnlock(Context *ctx, ThreadState *thr, SyncVar *s) {
|
||||||
if (!common_flags()->detect_deadlocks) return;
|
if (!common_flags()->detect_deadlocks) return;
|
||||||
if (s->recursion != 0) return;
|
if (s->recursion != 0) return;
|
||||||
Lock lk(&ctx->dd_mtx);
|
|
||||||
EnsureDeadlockDetectorID(ctx, thr, s);
|
|
||||||
// Printf("T%d MutexUnlock: %zx; recursion %d\n", thr->tid,
|
// Printf("T%d MutexUnlock: %zx; recursion %d\n", thr->tid,
|
||||||
// s->deadlock_detector_id, s->recursion);
|
// s->deadlock_detector_id, s->recursion);
|
||||||
ctx->dd.onUnlock(&thr->deadlock_detector_tls, s->deadlock_detector_id);
|
ctx->dd.onUnlock(&thr->deadlock_detector_tls, s->deadlock_detector_id);
|
||||||
|
|
Loading…
Reference in New Issue