# HG changeset patch # User Andreas Pehrson # Date 1513760551 -3600 # Wed Dec 20 10:02:31 2017 +0100 # Node ID 7989fd5fee8ac0188bedbafd7a96950000224846 # Parent 201ae9cd05c695ea07694a1462f121f88caf518c Bug 1299515 - Implement MediaTimer::Cancel to allow for rejecting timer promises. r=jya MozReview-Commit-ID: ESLlbIS8XHa diff --git a/dom/media/MediaTimer.cpp b/dom/media/MediaTimer.cpp --- a/dom/media/MediaTimer.cpp +++ b/dom/media/MediaTimer.cpp @@ -53,22 +53,20 @@ MediaTimer::DispatchDestroy() } void MediaTimer::Destroy() { MOZ_ASSERT(OnMediaTimerThread()); TIMER_LOG("MediaTimer::Destroy"); - // Reject any outstanding entries. There's no need to acquire the monitor - // here, because we're on the timer thread and all other references to us - // must be gone. - while (!mEntries.empty()) { - mEntries.top().mPromise->Reject(false, __func__); - mEntries.pop(); + // Reject any outstanding entries. + { + MonitorAutoLock lock(mMonitor); + Reject(); } // Cancel the timer if necessary. CancelTimerIfArmed(); delete this; } @@ -94,16 +92,24 @@ MediaTimer::WaitUntil(const TimeStamp& a Entry e(aTimeStamp, aCallSite); RefPtr p = e.mPromise.get(); mEntries.push(e); ScheduleUpdate(); return p; } void +MediaTimer::Cancel() +{ + MonitorAutoLock mon(mMonitor); + TIMER_LOG("MediaTimer::Cancel"); + Reject(); +} + +void MediaTimer::ScheduleUpdate() { mMonitor.AssertCurrentThreadOwns(); if (mUpdateScheduled) { return; } mUpdateScheduled = true; @@ -161,16 +167,26 @@ MediaTimer::UpdateLocked() // We've got more entries - (re)arm the timer for the soonest one. if (!TimerIsArmed() || mEntries.top().mTimeStamp < mCurrentTimerTarget) { CancelTimerIfArmed(); ArmTimer(mEntries.top().mTimeStamp, now); } } +void +MediaTimer::Reject() +{ + mMonitor.AssertCurrentThreadOwns(); + while (!mEntries.empty()) { + mEntries.top().mPromise->Reject(false, __func__); + mEntries.pop(); + } +} + /* * We use a callback function, rather than a callback method, to ensure that * the nsITimer does not artifically keep the refcount of the MediaTimer above * zero. When the MediaTimer is destroyed, it safely cancels the nsITimer so that * we never fire against a dangling closure. */ /* static */ void diff --git a/dom/media/MediaTimer.h b/dom/media/MediaTimer.h --- a/dom/media/MediaTimer.h +++ b/dom/media/MediaTimer.h @@ -39,28 +39,30 @@ public: explicit MediaTimer(bool aFuzzy = false); // We use a release with a custom Destroy(). NS_IMETHOD_(MozExternalRefCountType) AddRef(void); NS_IMETHOD_(MozExternalRefCountType) Release(void); RefPtr WaitFor(const TimeDuration& aDuration, const char* aCallSite); RefPtr WaitUntil(const TimeStamp& aTimeStamp, const char* aCallSite); + void Cancel(); // Cancel and reject any unresolved promises with false. private: virtual ~MediaTimer() { MOZ_ASSERT(OnMediaTimerThread()); } void DispatchDestroy(); // Invoked by Release on an arbitrary thread. void Destroy(); // Runs on the timer thread. bool OnMediaTimerThread(); void ScheduleUpdate(); void Update(); void UpdateLocked(); bool IsExpired(const TimeStamp& aTarget, const TimeStamp& aNow); + void Reject(); static void TimerCallback(nsITimer* aTimer, void* aClosure); void TimerFired(); void ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow); bool TimerIsArmed() { return !mCurrentTimerTarget.IsNull();