Bug 1366845 - Use XPCOM threads for hang monitor (r=mrbkap)

MozReview-Commit-ID: 3zMWYDATDch
This commit is contained in:
Bill McCloskey 2017-05-19 20:36:10 -07:00
parent dfcc5830e0
commit ab129f71c8
2 changed files with 76 additions and 63 deletions

View File

@ -110,7 +110,11 @@ class HangMonitorChild
static HangMonitorChild* Get() { return sInstance; }
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
void Dispatch(already_AddRefed<nsIRunnable> 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<nsIRunnable> 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<PProcessHangMonitorChild>&& 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
<TabId, nsCString>(this,
&HangMonitorChild::NotifySlowScriptAsync,
id, filename));
Dispatch(NewNonOwningRunnableMethod
<TabId, nsCString>(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<uint32_t>(this,
&HangMonitorChild::NotifyPluginHangAsync,
aPluginId));
Dispatch(NewNonOwningRunnableMethod<uint32_t>(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<TabId, uint64_t>(
this, &HangMonitorParent::ForcePaintOnThread, id, aLayerObserverEpoch));
Dispatch(NewNonOwningRunnableMethod
<TabId, uint64_t>(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<PProcessHangMonitorParent>&& aEndpoint)
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
MOZ_RELEASE_ASSERT(IsOnThread());
DebugOnly<bool> 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
<Endpoint<PProcessHangMonitorParent>&&>(parent,
&HangMonitorParent::Bind,
Move(aEndpoint)));
monitor->Dispatch(NewNonOwningRunnableMethod
<Endpoint<PProcessHangMonitorParent>&&>(parent,
&HangMonitorParent::Bind,
Move(aEndpoint)));
return parent;
}
@ -1171,16 +1178,23 @@ mozilla::CreateHangMonitorChild(Endpoint<PProcessHangMonitorChild>&& aEndpoint)
ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
auto* child = new HangMonitorChild(monitor);
monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod
<Endpoint<PProcessHangMonitorChild>&&>(child,
&HangMonitorChild::Bind,
Move(aEndpoint)));
monitor->Dispatch(NewNonOwningRunnableMethod
<Endpoint<PProcessHangMonitorChild>&&>(child,
&HangMonitorChild::Bind,
Move(aEndpoint)));
}
MessageLoop*
ProcessHangMonitor::MonitorLoop()
void
ProcessHangMonitor::Dispatch(already_AddRefed<nsIRunnable> 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*

View File

@ -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<nsIRunnable> aRunnable);
bool IsOnThread();
private:
static ProcessHangMonitor* sInstance;
Atomic<bool> mCPOWTimeout;
base::Thread* mThread;
nsCOMPtr<nsIThread> mThread;
};
} // namespace mozilla