diff options
author | Moonchild <moonchild@palemoon.org> | 2022-03-08 22:32:28 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-05-30 08:18:26 +0000 |
commit | 2705986b4a7977a30a18b20945ef072c4e32b89f (patch) | |
tree | 4b82d7d025599699ab6d336f90586d4b0902503c | |
parent | 8e42fccca66d06b664ecc3c7345dc787a26ef4d9 (diff) | |
download | uxp-2705986b4a7977a30a18b20945ef072c4e32b89f.tar.gz |
[xpcom] Timer cleanup, assertions and comments.
-rw-r--r-- | xpcom/threads/TimerThread.cpp | 20 | ||||
-rw-r--r-- | xpcom/threads/TimerThread.h | 4 | ||||
-rw-r--r-- | xpcom/threads/nsTimerImpl.cpp | 2 | ||||
-rw-r--r-- | xpcom/threads/nsTimerImpl.h | 5 |
4 files changed, 24 insertions, 7 deletions
diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index db7c924623..c2a0284eca 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -634,10 +634,13 @@ TimerThread::AddTimerInternal(nsTimerImpl* aTimer) return insertSlot - mTimers.Elements(); } +// This function must be called from within a lock. +// Also: we hold the mutex for the nsTimerImpl. bool TimerThread::RemoveTimerInternal(nsTimerImpl* aTimer) { mMonitor.AssertCurrentThreadOwns(); + aTimer->mMutex.AssertCurrentThreadOwns(); if (!mTimers.RemoveElement(aTimer)) { return false; } @@ -701,12 +704,17 @@ TimerThread::PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef) // at the TimerThread we'll deadlock. MonitorAutoUnlock unlock(mMonitor); rv = target->Dispatch(event, NS_DISPATCH_NORMAL); - } - - if (NS_FAILED(rv)) { - timer = event->ForgetTimer(); - RemoveTimerInternal(timer); - return timer.forget(); + if (NS_FAILED(rv)) { + timer = event->ForgetTimer(); + // We do this to avoid possible deadlock by taking the two locks in a + // different order than is used in RemoveTimer(). RemoveTimer() has + // aTimer->mMutex first. We use timer.get() to keep static analysis + // happy. + MutexAutoLock lock1(timer.get()->mMutex); + MonitorAutoLock lock2(mMonitor); + RemoveTimerInternal(timer.get()); + return timer.forget(); + } } return nullptr; diff --git a/xpcom/threads/TimerThread.h b/xpcom/threads/TimerThread.h index 4d4b7be77d..c82f3ec7f5 100644 --- a/xpcom/threads/TimerThread.h +++ b/xpcom/threads/TimerThread.h @@ -69,6 +69,10 @@ private: already_AddRefed<nsTimerImpl> PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef); nsCOMPtr<nsIThread> mThread; + // Lock ordering requirements: + // (optional) ThreadWrapper::sMutex -> + // (optional) nsTimerImpl::mMutex -> + // TimerThread::mMonitor Monitor mMonitor; bool mShutdown; diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index 830315cefa..cac3e86929 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -439,6 +439,8 @@ nsTimerImpl::Fire(int32_t aGeneration) // If some other thread Cancels/Inits after this, they're just too late. MutexAutoLock lock(mMutex); if (aGeneration != mGeneration) { + // This timer got rescheduled or cancelled before we fired, so ignore this + // firing return; } diff --git a/xpcom/threads/nsTimerImpl.h b/xpcom/threads/nsTimerImpl.h index 9d59b4e672..039294995d 100644 --- a/xpcom/threads/nsTimerImpl.h +++ b/xpcom/threads/nsTimerImpl.h @@ -166,7 +166,10 @@ public: int32_t mGeneration; uint32_t mDelay; - // Updated only after this timer has been removed from the timer thread. + // Never updated while in the TimerThread's timer list. Only updated + // before adding to that list or during nsTimerImpl::Fire(), when it has + // been removed from the TimerThread's list. TimerThread can safely access + // mTimeout of any timer in the list. TimeStamp mTimeout; #ifdef MOZ_TASK_TRACER |