#if ART_USE_FUTEXES staticinlineint futex(volatileint *uaddr, int op, int val, conststruct timespec *timeout, volatileint *uaddr2, int val3) { return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
} #endif// ART_USE_FUTEXES
// The following isn't strictly necessary, but we want updates on Atomic<pid_t> to be lock-free. // TODO: Use std::atomic::is_always_lock_free after switching to C++17 atomics.
static_assert(sizeof(pid_t) <= sizeof(int32_t), "pid_t should fit in 32 bits");
staticinlinevoid CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS { // The check below enumerates the cases where we expect not to be able to check the validity of // locks on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock. // TODO: tighten this check.
CHECK(!Locks::IsSafeToCallAbortRacy() || // Used during thread creation to avoid races with runtime shutdown. Thread::Current not // yet established.
level == kRuntimeShutdownLock || // Thread Ids are allocated/released before threads are established.
level == kAllocatedThreadIdsLock || // Thread LDT's are initialized without Thread::Current established.
level == kModifyLdtLock || // Threads are unregistered while holding the thread list lock, during this process they // no longer exist and so we expect an unlock with no self.
level == kThreadListLock || // Ignore logging which may or may not have set up thread data structures.
level == kLoggingLock || // When transitioning from suspended to runnable, a daemon thread might be in // a situation where the runtime is shutting down. To not crash our debug locking // mechanism we just pass null Thread* to the MutexLock during that transition // (see Thread::TransitionFromSuspendedToRunnable).
level == kThreadSuspendCountLock || // Avoid recursive death.
level == kAbortLock || // Locks at the absolute top of the stack can be locked at any time.
level == kTopLockLevel || // The unexpected signal handler may be catching signals from any thread.
level == kUnexpectedSignalLock)
<< level;
}
inlinevoid BaseMutex::RegisterAsLockedImpl(Thread* self, LockLevel level, bool check) {
DCHECK(self != nullptr);
DCHECK_EQ(level_, level); // It would be nice to avoid this condition checking in the non-debug case, // but that would make the various methods that check if a mutex is held not // work properly for thread wait locks. Since the vast majority of lock // acquisitions are not thread wait locks, this check should not be too // expensive. if (UNLIKELY(level == kThreadWaitLock) && self->GetHeldMutex(kThreadWaitLock) != nullptr) {
level = kThreadWaitWakeLock;
} if (check) { // Check if a bad Mutex of this level or lower is held. bool bad_mutexes_held = false; // Specifically allow a kTopLockLevel lock to be gained when the current thread holds the // mutator_lock_ exclusive. This is because we suspending when holding locks at this level is // not allowed and if we hold the mutator_lock_ exclusive we must unsuspend stuff eventually // so there are no deadlocks. if (level == kTopLockLevel &&
Locks::mutator_lock_->IsSharedHeld(self) &&
!Locks::mutator_lock_->IsExclusiveHeld(self)) {
LOG(ERROR) << "Lock level violation: holding \"" << Locks::mutator_lock_->name_ << "\" "
<< "(level " << kMutatorLock << " - " << static_cast<int>(kMutatorLock)
<< ") non-exclusive while locking \"" << name_ << "\" "
<< "(level " << level << " - " << static_cast<int>(level) << ") a top level"
<< "mutex. This is not allowed.";
bad_mutexes_held = true;
} elseif (this == Locks::mutator_lock_ && self->GetHeldMutex(kTopLockLevel) != nullptr) {
LOG(ERROR) << "Lock level violation. Locking mutator_lock_ while already having a "
<< "kTopLevelLock (" << self->GetHeldMutex(kTopLockLevel)->name_ << "held is "
<< "not allowed.";
bad_mutexes_held = true;
} for (int i = level; i >= 0; --i) {
LockLevel lock_level_i = static_cast<LockLevel>(i);
BaseMutex* held_mutex = self->GetHeldMutex(lock_level_i); if (level == kTopLockLevel &&
lock_level_i == kMutatorLock &&
Locks::mutator_lock_->IsExclusiveHeld(self)) { // This is checked above. continue;
} elseif (UNLIKELY(held_mutex != nullptr) && lock_level_i != kAbortLock) {
LOG(ERROR) << "Lock level violation: holding \"" << held_mutex->name_ << "\" "
<< "(level " << lock_level_i << " - " << i
<< ") while locking \"" << name_ << "\" "
<< "(level " << level << " - " << static_cast<int>(level) << ")"; if (lock_level_i > kAbortLock) { // Only abort in the check below if this is more than abort level lock.
bad_mutexes_held = true;
}
}
} if (gAborting == 0) { // Avoid recursive aborts.
CHECK(!bad_mutexes_held);
}
} // Don't record monitors as they are outside the scope of analysis. They may be inspected off of // the monitor list. if (level != kMonitorLock) {
self->SetHeldMutex(level, this);
}
}
inlinevoid Mutex::ExclusiveLockUncontendedForSelfId(pid_t selfId) {
DCHECK_EQ(level_, kMonitorLock);
DCHECK(!recursive_);
state_and_contenders_.store(kHeldMask, std::memory_order_relaxed);
recursion_count_ = 1;
exclusive_owner_.store(selfId, std::memory_order_relaxed); // Don't call RegisterAsLocked(). It wouldn't register anything anyway. And // this happens as we're inflating a monitor, which doesn't logically affect // held "locks"; it effectively just converts a thin lock to a mutex. By doing // this while the lock is already held, we're delaying the acquisition of a // logically held mutex, which can introduce bogus lock order violations.
}
inlinebool ReaderWriterMutex::IsExclusiveHeld(const Thread* self) const {
DCHECK(self == nullptr || self == Thread::Current()); bool result = (GetExclusiveOwnerTid() == SafeGetTid(self)); if (kDebugLocking) { // Verify that if the pthread thinks we own the lock the Thread agrees. if (self != nullptr && result) {
CHECK_EQ(self->GetHeldMutex(level_), this);
}
} return result;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.