Bug 1299515 - Implement MediaTimer::Cancel to allow for rejecting timer promises. r?jya
MozReview-Commit-ID: ESLlbIS8XHa
--- a/dom/media/MediaTimer.cpp
+++ b/dom/media/MediaTimer.cpp
@@ -52,22 +52,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;
}
@@ -93,16 +91,24 @@ MediaTimer::WaitUntil(const TimeStamp& a
Entry e(aTimeStamp, aCallSite);
RefPtr<MediaTimerPromise> 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;
@@ -160,16 +166,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
--- 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<MediaTimerPromise> WaitFor(const TimeDuration& aDuration, const char* aCallSite);
RefPtr<MediaTimerPromise> 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();