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-05-30 08:18:26 +0000
commit2705986b4a7977a30a18b20945ef072c4e32b89f (patch)
tree4b82d7d025599699ab6d336f90586d4b0902503c /xpcom
parent8e42fccca66d06b664ecc3c7345dc787a26ef4d9 (diff)
downloaduxp-2705986b4a7977a30a18b20945ef072c4e32b89f.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 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