From 4c1f33b169b74dce2af414db30fcf113c4bf2a56 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 10 Sep 2018 22:12:07 +0200 Subject: Bug 1470260 - Part 1: Ensure that 'this' stays alive for the duration of the TickRefreshDriver call. --- layout/base/nsRefreshDriver.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'layout/base/nsRefreshDriver.cpp') diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index bc1a27852..8a62b517e 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -478,6 +478,9 @@ private: bool NotifyVsync(TimeStamp aVsyncTimestamp) override { + // IMPORTANT: All paths through this method MUST hold a strong ref on + // |this| for the duration of the TickRefreshDriver callback. + if (!NS_IsMainThread()) { MOZ_ASSERT(XRE_IsParentProcess()); // Compress vsync notifications such that only 1 may run at a time @@ -498,6 +501,7 @@ private: aVsyncTimestamp); NS_DispatchToMainThread(vsyncEvent); } else { + RefPtr kungFuDeathGrip(this); TickRefreshDriver(aVsyncTimestamp); } -- cgit v1.2.3 From 69b88dfccc38b9022e65bf459b199bdf4145ce67 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 10 Sep 2018 22:22:16 +0200 Subject: Bug 1470260 - Part 2: Make RefreshDriverTimer ref-counted and hold a strong ref on it on the stack when nsRefreshDriver::Tick can be reached. --- layout/base/nsRefreshDriver.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'layout/base/nsRefreshDriver.cpp') diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 8a62b517e..b975a69dd 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -143,11 +143,7 @@ public: { } - virtual ~RefreshDriverTimer() - { - MOZ_ASSERT(mContentRefreshDrivers.Length() == 0, "Should have removed all content refresh drivers from here by now!"); - MOZ_ASSERT(mRootRefreshDrivers.Length() == 0, "Should have removed all root refresh drivers from here by now!"); - } + NS_INLINE_DECL_REFCOUNTING(RefreshDriverTimer) virtual void AddRefreshDriver(nsRefreshDriver* aDriver) { @@ -253,6 +249,12 @@ public: } protected: + virtual ~RefreshDriverTimer() + { + MOZ_ASSERT(mContentRefreshDrivers.Length() == 0, "Should have removed all content refresh drivers from here by now!"); + MOZ_ASSERT(mRootRefreshDrivers.Length() == 0, "Should have removed all root refresh drivers from here by now!"); + } + virtual void StartTimer() = 0; virtual void StopTimer() = 0; virtual void ScheduleNextTick(TimeStamp aNowTime) = 0; @@ -335,10 +337,11 @@ protected: nsTArray > mRootRefreshDrivers; // useful callback for nsITimer-based derived classes, here - // bacause of c++ protected shenanigans + // because of c++ protected shenanigans static void TimerTick(nsITimer* aTimer, void* aClosure) { - RefreshDriverTimer *timer = static_cast(aClosure); + RefPtr timer = + static_cast(aClosure); timer->Tick(); } }; @@ -459,9 +462,7 @@ public: private: // Since VsyncObservers are refCounted, but the RefreshDriverTimer are // explicitly shutdown. We create an inner class that has the VsyncObserver - // and is shutdown when the RefreshDriverTimer is deleted. The alternative is - // to (a) make all RefreshDriverTimer RefCounted or (b) use different - // VsyncObserver types. + // and is shutdown when the RefreshDriverTimer is deleted. class RefreshDriverVsyncObserver final : public VsyncObserver { public: @@ -576,7 +577,9 @@ private: // the scheduled TickRefreshDriver() runs. Check mVsyncRefreshDriverTimer // before use. if (mVsyncRefreshDriverTimer) { - mVsyncRefreshDriverTimer->RunRefreshDrivers(aVsyncTimestamp); + RefPtr timer = mVsyncRefreshDriverTimer; + timer->RunRefreshDrivers(aVsyncTimestamp); + // Note: mVsyncRefreshDriverTimer might be null now. } } @@ -829,7 +832,8 @@ protected: static void TimerTickOne(nsITimer* aTimer, void* aClosure) { - InactiveRefreshDriverTimer *timer = static_cast(aClosure); + RefPtr timer = + static_cast(aClosure); timer->TickOne(); } @@ -881,8 +885,8 @@ NS_IMPL_ISUPPORTS(VsyncChildCreateCallback, nsIIPCBackgroundChildCreateCallback) } // namespace mozilla -static RefreshDriverTimer* sRegularRateTimer; -static InactiveRefreshDriverTimer* sThrottledRateTimer; +static StaticRefPtr sRegularRateTimer; +static StaticRefPtr sThrottledRateTimer; #ifdef XP_WIN static int32_t sHighPrecisionTimerRequests = 0; @@ -964,8 +968,6 @@ GetFirstFrameDelay(imgIRequest* req) nsRefreshDriver::Shutdown() { // clean up our timers - delete sRegularRateTimer; - delete sThrottledRateTimer; sRegularRateTimer = nullptr; sThrottledRateTimer = nullptr; @@ -2229,16 +2231,15 @@ nsRefreshDriver::PVsyncActorCreated(VsyncChild* aVsyncChild) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!XRE_IsParentProcess()); - auto* vsyncRefreshDriverTimer = - new VsyncRefreshDriverTimer(aVsyncChild); + RefPtr vsyncRefreshDriverTimer = + new VsyncRefreshDriverTimer(aVsyncChild); // If we are using software timer, swap current timer to // VsyncRefreshDriverTimer. if (sRegularRateTimer) { sRegularRateTimer->SwapRefreshDrivers(vsyncRefreshDriverTimer); - delete sRegularRateTimer; } - sRegularRateTimer = vsyncRefreshDriverTimer; + sRegularRateTimer = vsyncRefreshDriverTimer.forget(); } void -- cgit v1.2.3