summaryrefslogtreecommitdiff
path: root/xpcom
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2022-03-08 22:32:28 +0000
committerMoonchild <moonchild@palemoon.org>2022-03-21 13:25:31 +0000
commit783dd1707f424e10b9297e49908dc33e0861b2dc (patch)
tree40a36be00d246570885511ba3e38f6addc463bc8 /xpcom
parenta957e8b299c352afb7472b2e6df95c8bf62c4dc0 (diff)
downloadaura-central-783dd1707f424e10b9297e49908dc33e0861b2dc.tar.gz
[xpcom] Timer cleanup, assertions and comments.
Diffstat (limited to 'xpcom')
-rw-r--r--xpcom/threads/TimerThread.cpp20
-rw-r--r--xpcom/threads/TimerThread.h4
-rw-r--r--xpcom/threads/nsTimerImpl.cpp2
-rw-r--r--xpcom/threads/nsTimerImpl.h5
4 files changed, 24 insertions, 7 deletions
diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp
index 36168e373..a2e40c388 100644
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -623,10 +623,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;
}
@@ -690,12 +693,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 4d4b7be77..c82f3ec7f 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 3ca54fd61..1a200a6b3 100644
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -443,6 +443,8 @@ nsTimerImpl::Fire(int32_t aGeneration)
// Don't fire callbacks or fiddle with refcounts when the mutex is locked.
// If some other thread Cancels/Inits after this, they're just too late.
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 9d59b4e67..039294995 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