From ab129f71c8409433a61438c8a8d6ea27331281a6 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 19 May 2017 20:36:10 -0700 Subject: [PATCH] Bug 1366845 - Use XPCOM threads for hang monitor (r=mrbkap) MozReview-Commit-ID: 3zMWYDATDch --- dom/ipc/ProcessHangMonitor.cpp | 124 ++++++++++++++++++--------------- dom/ipc/ProcessHangMonitor.h | 15 ++-- 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index d3eb206629b4..91f605cb8b0e 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -110,7 +110,11 @@ class HangMonitorChild static HangMonitorChild* Get() { return sInstance; } - MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); } + void Dispatch(already_AddRefed aRunnable) + { + mHangMonitor->Dispatch(Move(aRunnable)); + } + bool IsOnThread() { return mHangMonitor->IsOnThread(); } private: void ShutdownOnThread(); @@ -234,7 +238,11 @@ public: */ void UpdateMinidump(uint32_t aPluginId, const nsString& aDumpId); - MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); } + void Dispatch(already_AddRefed aRunnable) + { + mHangMonitor->Dispatch(Move(aRunnable)); + } + bool IsOnThread() { return mHangMonitor->IsOnThread(); } private: bool TakeBrowserMinidump(const PluginHangData& aPhd, nsString& aCrashId); @@ -345,7 +353,7 @@ HangMonitorChild::Shutdown() void HangMonitorChild::ShutdownOnThread() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); MonitorAutoLock lock(mMonitor); mShutdownDone = true; @@ -355,19 +363,19 @@ HangMonitorChild::ShutdownOnThread() void HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); mIPCOpen = false; // We use a task here to ensure that IPDL is finished with this // HangMonitorChild before it gets deleted on the main thread. - MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, &HangMonitorChild::ShutdownOnThread)); + Dispatch(NewNonOwningRunnableMethod(this, &HangMonitorChild::ShutdownOnThread)); } mozilla::ipc::IPCResult HangMonitorChild::RecvTerminateScript() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); MonitorAutoLock lock(mMonitor); mTerminateScript = true; @@ -377,7 +385,7 @@ HangMonitorChild::RecvTerminateScript() mozilla::ipc::IPCResult HangMonitorChild::RecvBeginStartingDebugger() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); MonitorAutoLock lock(mMonitor); mStartDebugger = true; @@ -387,7 +395,7 @@ HangMonitorChild::RecvBeginStartingDebugger() mozilla::ipc::IPCResult HangMonitorChild::RecvEndStartingDebugger() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); MonitorAutoLock lock(mMonitor); mFinishedStartingDebugger = true; @@ -397,7 +405,7 @@ HangMonitorChild::RecvEndStartingDebugger() mozilla::ipc::IPCResult HangMonitorChild::RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); mForcePaintMonitor->NotifyActivity(); @@ -425,7 +433,7 @@ HangMonitorChild::ClearForcePaint() void HangMonitorChild::Bind(Endpoint&& aEndpoint) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); MOZ_ASSERT(!sInstance); sInstance = this; @@ -472,10 +480,10 @@ HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild, } nsAutoCString filename(aFileName); - MonitorLoop()->PostTask(NewNonOwningRunnableMethod - (this, - &HangMonitorChild::NotifySlowScriptAsync, - id, filename)); + Dispatch(NewNonOwningRunnableMethod + (this, + &HangMonitorChild::NotifySlowScriptAsync, + id, filename)); return SlowScriptAction::Continue; } @@ -503,15 +511,15 @@ HangMonitorChild::NotifyPluginHang(uint32_t aPluginId) mSentReport = true; // bounce to background thread - MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, - &HangMonitorChild::NotifyPluginHangAsync, - aPluginId)); + Dispatch(NewNonOwningRunnableMethod(this, + &HangMonitorChild::NotifyPluginHangAsync, + aPluginId)); } void HangMonitorChild::NotifyPluginHangAsync(uint32_t aPluginId) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); // bounce back to parent on background thread if (mIPCOpen) { @@ -527,7 +535,7 @@ HangMonitorChild::ClearHang() if (mSentReport) { // bounce to background thread - MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, &HangMonitorChild::ClearHangAsync)); + Dispatch(NewNonOwningRunnableMethod(this, &HangMonitorChild::ClearHangAsync)); MonitorAutoLock lock(mMonitor); mSentReport = false; @@ -540,7 +548,7 @@ HangMonitorChild::ClearHang() void HangMonitorChild::ClearHangAsync() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); // bounce back to parent on background thread if (mIPCOpen) { @@ -595,8 +603,8 @@ HangMonitorParent::Shutdown() mProcess = nullptr; } - MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, - &HangMonitorParent::ShutdownOnThread)); + Dispatch(NewNonOwningRunnableMethod(this, + &HangMonitorParent::ShutdownOnThread)); while (!mShutdownDone) { mMonitor.Wait(); @@ -606,7 +614,7 @@ HangMonitorParent::Shutdown() void HangMonitorParent::ShutdownOnThread() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); // mIPCOpen is only written from this thread, so need need to take the lock // here. We'd be shooting ourselves in the foot, because ActorDestroy takes @@ -626,15 +634,15 @@ HangMonitorParent::ForcePaint(dom::TabParent* aTab, uint64_t aLayerObserverEpoch MOZ_RELEASE_ASSERT(NS_IsMainThread()); if (sShouldForcePaint) { TabId id = aTab->GetTabId(); - MonitorLoop()->PostTask(NewNonOwningRunnableMethod( - this, &HangMonitorParent::ForcePaintOnThread, id, aLayerObserverEpoch)); + Dispatch(NewNonOwningRunnableMethod + (this, &HangMonitorParent::ForcePaintOnThread, id, aLayerObserverEpoch)); } } void HangMonitorParent::ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (mIPCOpen) { Unused << SendForcePaint(aTabId, aLayerObserverEpoch); @@ -644,14 +652,14 @@ HangMonitorParent::ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch void HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); mIPCOpen = false; } void HangMonitorParent::Bind(Endpoint&& aEndpoint) { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); DebugOnly ok = aEndpoint.Bind(this); MOZ_ASSERT(ok); @@ -729,7 +737,7 @@ mozilla::ipc::IPCResult HangMonitorParent::RecvHangEvidence(const HangData& aHangData) { // chrome process, background thread - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (!mReportHangs) { return IPC_OK(); @@ -767,7 +775,7 @@ mozilla::ipc::IPCResult HangMonitorParent::RecvClearHang() { // chrome process, background thread - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (!mReportHangs) { return IPC_OK(); @@ -787,7 +795,7 @@ HangMonitorParent::RecvClearHang() void HangMonitorParent::TerminateScript() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (mIPCOpen) { Unused << SendTerminateScript(); @@ -797,7 +805,7 @@ HangMonitorParent::TerminateScript() void HangMonitorParent::BeginStartingDebugger() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (mIPCOpen) { Unused << SendBeginStartingDebugger(); @@ -807,7 +815,7 @@ HangMonitorParent::BeginStartingDebugger() void HangMonitorParent::EndStartingDebugger() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); if (mIPCOpen) { Unused << SendEndStartingDebugger(); @@ -936,8 +944,8 @@ HangMonitoredProcess::TerminateScript() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, - &HangMonitorParent::TerminateScript)); + ProcessHangMonitor::Get()->Dispatch(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::TerminateScript)); return NS_OK; } @@ -953,8 +961,8 @@ HangMonitoredProcess::BeginStartingDebugger() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, - &HangMonitorParent::BeginStartingDebugger)); + ProcessHangMonitor::Get()->Dispatch(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::BeginStartingDebugger)); return NS_OK; } @@ -970,8 +978,8 @@ HangMonitoredProcess::EndStartingDebugger() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, - &HangMonitorParent::EndStartingDebugger)); + ProcessHangMonitor::Get()->Dispatch(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::EndStartingDebugger)); return NS_OK; } @@ -1052,9 +1060,7 @@ ProcessHangMonitor::ProcessHangMonitor() obs->AddObserver(this, "xpcom-shutdown", false); } - mThread = new base::Thread("ProcessHangMonitor"); - if (!mThread->Start()) { - delete mThread; + if (NS_FAILED(NS_NewNamedThread("ProcessHangMon", getter_AddRefs(mThread)))) { mThread = nullptr; } } @@ -1066,7 +1072,8 @@ ProcessHangMonitor::~ProcessHangMonitor() MOZ_ASSERT(sInstance == this); sInstance = nullptr; - delete mThread; + mThread->Shutdown(); + mThread = nullptr; } ProcessHangMonitor* @@ -1129,7 +1136,7 @@ ProcessHangMonitor::ShouldTimeOutCPOWs() void ProcessHangMonitor::InitiateCPOWTimeout() { - MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop()); + MOZ_RELEASE_ASSERT(IsOnThread()); mCPOWTimeout = true; } @@ -1152,10 +1159,10 @@ CreateHangMonitorParent(ContentParent* aContentParent, auto* process = new HangMonitoredProcess(parent, aContentParent); parent->SetProcess(process); - monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod - &&>(parent, - &HangMonitorParent::Bind, - Move(aEndpoint))); + monitor->Dispatch(NewNonOwningRunnableMethod + &&>(parent, + &HangMonitorParent::Bind, + Move(aEndpoint))); return parent; } @@ -1171,16 +1178,23 @@ mozilla::CreateHangMonitorChild(Endpoint&& aEndpoint) ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate(); auto* child = new HangMonitorChild(monitor); - monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod - &&>(child, - &HangMonitorChild::Bind, - Move(aEndpoint))); + monitor->Dispatch(NewNonOwningRunnableMethod + &&>(child, + &HangMonitorChild::Bind, + Move(aEndpoint))); } -MessageLoop* -ProcessHangMonitor::MonitorLoop() +void +ProcessHangMonitor::Dispatch(already_AddRefed aRunnable) { - return mThread->message_loop(); + mThread->Dispatch(Move(aRunnable), nsIEventTarget::NS_DISPATCH_NORMAL); +} + +bool +ProcessHangMonitor::IsOnThread() +{ + bool on; + return NS_SUCCEEDED(mThread->IsOnCurrentThread(&on)) && on; } /* static */ PProcessHangMonitorParent* diff --git a/dom/ipc/ProcessHangMonitor.h b/dom/ipc/ProcessHangMonitor.h index 1c0a1f76760b..b94b72168989 100644 --- a/dom/ipc/ProcessHangMonitor.h +++ b/dom/ipc/ProcessHangMonitor.h @@ -7,16 +7,14 @@ #ifndef mozilla_ProcessHangMonitor_h #define mozilla_ProcessHangMonitor_h +#include "mozilla/AlreadyAddRefed.h" #include "mozilla/Atomics.h" +#include "nsCOMPtr.h" #include "nsIObserver.h" +class nsIRunnable; class nsITabChild; - -class MessageLoop; - -namespace base { -class Thread; -} // namespace base +class nsIThread; namespace mozilla { @@ -66,14 +64,15 @@ class ProcessHangMonitor final void InitiateCPOWTimeout(); bool ShouldTimeOutCPOWs(); - MessageLoop* MonitorLoop(); + void Dispatch(already_AddRefed aRunnable); + bool IsOnThread(); private: static ProcessHangMonitor* sInstance; Atomic mCPOWTimeout; - base::Thread* mThread; + nsCOMPtr mThread; }; } // namespace mozilla