diff options
Diffstat (limited to 'xpcom/threads/TimerThread.cpp')
-rw-r--r-- | xpcom/threads/TimerThread.cpp | 35 |
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; |