diff options
author | 2022-09-14 22:45:40 +0000 | |
---|---|---|
committer | 2022-10-12 22:41:25 +0000 | |
commit | fd20a745227aa7cae7a08728bb29e5bfce64ea87 (patch) | |
tree | 3a39bacc9c52bfd68abb4976b083359636d8fc78 /runtime/base/mutex-inl.h | |
parent | 40bc9dc50978a7e8a7d41f551adef02ad2546254 (diff) |
Revert^2 "Thread suspension cleanup and deadlock fix"
This reverts commit 7c8835df16147b9096dd4c9380ab4b5f700ea17d.
PS1 is identical to aosp/2171862 .
PS2 makes the following significant changes:
1) Avoid inflating locks from the thread dumping checkpoint Run()
method. This violates the repeatedly stated claim that
checkpoint Run() methods don't suspend threads. This requires
that we print object addresses in thread dumps in some cases in
which we were previously able to give hashcodes instead.
2) For debug builds, check that we do not acquire a higher
level lock in checkpoint Run() methods, thus enforcing that
previously stated property. (Lokesh suggested this, and I
think it's a great idea. But it requires changes 4-6 below.)
3) Add a bit more justification that RunCheckpoint cannot
result in circular suspend requests.
4) For now, allow an explicit override of (2) for ddms code in
which it would otherwise fail. This should be fixed later.
5) Raise the level of monitor locks, to correctly reflect
the fact that they may be held while much of the runtime
is executed.
6) (5) was in conflict with monitor deflation acquiring a
monitor lock after acquiring the monitor list lock. But this
failure is spurious, both because it is a TryLock acquisition
that can't possibly contributed to a deadlock, and secondly
because it conflates all monitor locks, and an actual deadlock
is probably not possible anyway. Leverage the former and add
a facility to avoid checking for safe TryLock calls.
(1) Should fix the one failure I managed to debug after the
last submission attempt. Hopefully it also accounts for the
others.
PS3, PS5, PS6: Trivial corrections and cleanups
PS4, PS7, PS8: Rebase
Test: Build and boot AOSP, Treehugger
Bug: 240742796
Bug: 203363895
Bug: 238032384
Change-Id: I80d441ebe21bb30b586131f7d22b7f2797f2c45f
Diffstat (limited to 'runtime/base/mutex-inl.h')
-rw-r--r-- | runtime/base/mutex-inl.h | 74 |
1 files changed, 38 insertions, 36 deletions
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index dba1e1299b..a8dc95a86b 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -60,43 +60,43 @@ static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALY // 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. - if (kDebugLocking) { - 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; - } + 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; } -inline void BaseMutex::RegisterAsLocked(Thread* self) { +inline void BaseMutex::RegisterAsLocked(Thread* self, bool check) { if (UNLIKELY(self == nullptr)) { - CheckUnattachedThread(level_); - return; + if (check) { + CheckUnattachedThread(level_); + } + } else { + RegisterAsLockedImpl(self, level_, check); } - RegisterAsLockedImpl(self, level_); } -inline void BaseMutex::RegisterAsLockedImpl(Thread* self, LockLevel level) { +inline void 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, @@ -107,7 +107,7 @@ inline void BaseMutex::RegisterAsLockedImpl(Thread* self, LockLevel level) { if (UNLIKELY(level == kThreadWaitLock) && self->GetHeldMutex(kThreadWaitLock) != nullptr) { level = kThreadWaitWakeLock; } - if (kDebugLocking) { + 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 @@ -161,10 +161,12 @@ inline void BaseMutex::RegisterAsLockedImpl(Thread* self, LockLevel level) { inline void BaseMutex::RegisterAsUnlocked(Thread* self) { if (UNLIKELY(self == nullptr)) { - CheckUnattachedThread(level_); - return; + if (kDebugLocking) { + CheckUnattachedThread(level_); + } + } else { + RegisterAsUnlockedImpl(self , level_); } - RegisterAsUnlockedImpl(self , level_); } inline void BaseMutex::RegisterAsUnlockedImpl(Thread* self, LockLevel level) { @@ -306,7 +308,7 @@ inline void MutatorMutex::TransitionFromRunnableToSuspended(Thread* self) { } inline void MutatorMutex::TransitionFromSuspendedToRunnable(Thread* self) { - RegisterAsLockedImpl(self, kMutatorLock); + RegisterAsLockedImpl(self, kMutatorLock, kDebugLocking); AssertSharedHeld(self); } |