diff --git a/widget/windows/WinWindowOcclusionTracker.cpp b/widget/windows/WinWindowOcclusionTracker.cpp index e44a43835a1c..9aa339ea2c6a 100644 --- a/widget/windows/WinWindowOcclusionTracker.cpp +++ b/widget/windows/WinWindowOcclusionTracker.cpp @@ -18,6 +18,7 @@ #include "nsThreadUtils.h" #include "mozilla/DataMutex.h" #include "mozilla/gfx/Logging.h" +#include "mozilla/layers/SynchronousTask.h" #include "mozilla/TimeStamp.h" #include "mozilla/Logging.h" #include "mozilla/StaticPrefs_widget.h" @@ -335,30 +336,21 @@ void WinWindowOcclusionTracker::Ensure() { MOZ_ASSERT(NS_IsMainThread()); LOG(LogLevel::Info, "WinWindowOcclusionTracker::Ensure()"); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_UI; - if (sTracker) { - // Try to reuse the thread, which involves stopping and restarting it. - sTracker->mThread->Stop(); - if (sTracker->mThread->StartWithOptions(options)) { - // Success! - return; - } - // Restart failed, so null out our sTracker and try again with a new - // thread. This will cause the old singleton instance to be deallocated, - // which will destroy its mThread as well. - sTracker = nullptr; - } - - UniquePtr thread = - MakeUnique("WinWindowOcclusionCalc"); - - if (!thread->StartWithOptions(options)) { return; } - sTracker = new WinWindowOcclusionTracker(std::move(thread)); + base::Thread* thread = new base::Thread("WinWindowOcclusionCalc"); + + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_UI; + + if (!thread->StartWithOptions(options)) { + delete thread; + return; + } + + sTracker = new WinWindowOcclusionTracker(thread); WindowOcclusionCalculator::CreateInstance(); RefPtr runnable = @@ -370,46 +362,34 @@ void WinWindowOcclusionTracker::Ensure() { /* static */ void WinWindowOcclusionTracker::ShutDown() { + if (!sTracker) { + return; + } + MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(sTracker); LOG(LogLevel::Info, "WinWindowOcclusionTracker::ShutDown()"); sTracker->Destroy(); - // Our thread could hang while we're waiting for it to stop. - // Since we're shutting down, that's not a critical problem. - // We set a reasonable amount of time to wait for shutdown, - // and if it succeeds within that time, we correctly stop - // our thread by nulling out the refptr, which will cause it - // to be deallocated and join the thread. If it times out, - // we do nothing, which means that the thread will not be - // joined and sTracker memory will leak. - static const TimeDuration TIMEOUT = TimeDuration::FromSeconds(2.0); + // Our shutdown task could hang. Since we're shutting down, + // that's not a critical problem. We set a reasonable amount + // of time to wait for shutdown, and if it succeeds within + // that time, we correctly stop our tracker thread. If it + // times out, we just leak the memory and proceed. + static const PRIntervalTime TIMEOUT = PR_TicksPerSecond() * 2; + layers::SynchronousTask task("WinWindowOcclusionTracker"); RefPtr runnable = WrapRunnable(RefPtr( WindowOcclusionCalculator::GetInstance()), - &WindowOcclusionCalculator::Shutdown); + &WindowOcclusionCalculator::Shutdown, &task); OcclusionCalculatorLoop()->PostTask(runnable.forget()); - - CVStatus status; - { - MonitorAutoLock lock(sTracker->mMonitor); - - // Monitor uses SleepConditionVariableSRW, which can have - // spurious wakeups which are reported as timeouts, so we - // check timestamps to ensure that we've waited as long we - // intended to. - TimeStamp timeStart = TimeStamp::NowLoRes(); - do { - status = sTracker->mMonitor.Wait(TIMEOUT); - } while ((status == CVStatus::Timeout) && - ((TimeStamp::NowLoRes() - timeStart) < TIMEOUT)); + nsresult rv = task.Wait(TIMEOUT); + if (rv == NS_OK) { + sTracker->mThread->Stop(); } - if (status == CVStatus::NoTimeout) { - WindowOcclusionCalculator::ClearInstance(); - sTracker = nullptr; - } + WindowOcclusionCalculator::ClearInstance(); + sTracker = nullptr; } void WinWindowOcclusionTracker::Destroy() { @@ -506,9 +486,8 @@ void WinWindowOcclusionTracker::OnWindowVisibilityChanged(nsBaseWidget* aWindow, mSerializedTaskDispatcher->PostTaskToCalculator(runnable.forget()); } -WinWindowOcclusionTracker::WinWindowOcclusionTracker( - UniquePtr aThread) - : mThread(std::move(aThread)), mMonitor("WinWindowOcclusionTracker") { +WinWindowOcclusionTracker::WinWindowOcclusionTracker(base::Thread* aThread) + : mThread(aThread) { MOZ_ASSERT(NS_IsMainThread()); LOG(LogLevel::Info, "WinWindowOcclusionTracker::WinWindowOcclusionTracker()"); @@ -527,6 +506,7 @@ WinWindowOcclusionTracker::~WinWindowOcclusionTracker() { MOZ_ASSERT(NS_IsMainThread()); LOG(LogLevel::Info, "WinWindowOcclusionTracker::~WinWindowOcclusionTracker()"); + delete mThread; } // static @@ -835,8 +815,7 @@ StaticRefPtr WinWindowOcclusionTracker::WindowOcclusionCalculator::sCalculator; WinWindowOcclusionTracker::WindowOcclusionCalculator:: - WindowOcclusionCalculator() - : mMonitor(WinWindowOcclusionTracker::Get()->mMonitor) { + WindowOcclusionCalculator() { MOZ_ASSERT(NS_IsMainThread()); LOG(LogLevel::Info, "WindowOcclusionCalculator()"); @@ -880,20 +859,19 @@ void WinWindowOcclusionTracker::WindowOcclusionCalculator::Initialize() { #endif } -void WinWindowOcclusionTracker::WindowOcclusionCalculator::Shutdown() { - MonitorAutoLock lock(mMonitor); - +void WinWindowOcclusionTracker::WindowOcclusionCalculator::Shutdown( + layers::SynchronousTask* aTask) { MOZ_ASSERT(IsInWinWindowOcclusionThread()); CALC_LOG(LogLevel::Info, "Shutdown()"); + layers::AutoCompleteTask complete(aTask); + UnregisterEventHooks(); if (mOcclusionUpdateRunnable) { mOcclusionUpdateRunnable->Cancel(); mOcclusionUpdateRunnable = nullptr; } mVirtualDesktopManager = nullptr; - - mMonitor.NotifyAll(); } void WinWindowOcclusionTracker::WindowOcclusionCalculator:: diff --git a/widget/windows/WinWindowOcclusionTracker.h b/widget/windows/WinWindowOcclusionTracker.h index 8fb714db7556..924c48d87d75 100644 --- a/widget/windows/WinWindowOcclusionTracker.h +++ b/widget/windows/WinWindowOcclusionTracker.h @@ -13,7 +13,6 @@ #include #include "nsIWeakReferenceUtils.h" -#include "mozilla/Monitor.h" #include "mozilla/ThreadSafeWeakPtr.h" #include "mozilla/widget/WindowOcclusionState.h" #include "mozilla/widget/WinEventObserver.h" @@ -29,6 +28,10 @@ class Thread; namespace mozilla { +namespace layers { +class SynchronousTask; +} + namespace widget { class OcclusionUpdateRunnable; @@ -86,7 +89,7 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener, friend class ::WinWindowOcclusionTrackerTest; friend class ::WinWindowOcclusionTrackerInteractiveTest; - explicit WinWindowOcclusionTracker(UniquePtr aThread); + explicit WinWindowOcclusionTracker(base::Thread* aThread); virtual ~WinWindowOcclusionTracker(); // This class computes the occlusion state of the tracked windows. @@ -105,7 +108,7 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener, static WindowOcclusionCalculator* GetInstance() { return sCalculator; } void Initialize(); - void Shutdown(); + void Shutdown(layers::SynchronousTask* aTask); void EnableOcclusionTrackingForWindow(HWND hwnd); void DisableOcclusionTrackingForWindow(HWND hwnd); @@ -249,10 +252,6 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener, // Used to serialize tasks related to mRootWindowHwndsOcclusionState. RefPtr mSerializedTaskDispatcher; - // This is an alias to the singleton WinWindowOcclusionTracker mMonitor, - // and is used in ShutDown(). - Monitor& mMonitor; - friend class OcclusionUpdateRunnable; }; @@ -291,8 +290,7 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener, static StaticRefPtr sTracker; // "WinWindowOcclusionCalc" thread. - UniquePtr mThread; - Monitor mMonitor; + base::Thread* const mThread; // Map of HWND to widget. Maintained on main thread, and used to send // occlusion state notifications to Windows from