summaryrefslogtreecommitdiff
path: root/xpcom/threads/TimerThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/TimerThread.cpp')
-rw-r--r--xpcom/threads/TimerThread.cpp35
1 files changed, 16 insertions, 19 deletions
diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp
index db7c924623..a2e40c3880 100644
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -140,11 +140,7 @@ public:
nsresult Cancel() override
{
- // Since nsTimerImpl is not thread-safe, we should release |mTimer|
- // here in the target thread to avoid race condition. Otherwise,
- // ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the
- // timer thread and result in race condition.
- mTimer = nullptr;
+ mTimer->Cancel();
return NS_OK;
}
@@ -269,11 +265,6 @@ nsTimerEvent::DeleteAllocatorIfNeeded()
NS_IMETHODIMP
nsTimerEvent::Run()
{
- if (!mTimer) {
- MOZ_ASSERT(false);
- return NS_OK;
- }
-
if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
TimeStamp now = TimeStamp::Now();
MOZ_LOG(GetTimerLog(), LogLevel::Debug,
@@ -283,9 +274,7 @@ nsTimerEvent::Run()
mTimer->Fire(mGeneration);
- // We call Cancel() to correctly release mTimer.
- // Read more in the Cancel() implementation.
- return Cancel();
+ return NS_OK;
}
nsresult
@@ -634,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;
}
@@ -701,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;