Bug 1303077 - Annotate hangs that occur on the content process main thread during paint forcing. r?aklotz,billm
MozReview-Commit-ID: 9UBsoy5sIJE
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -11,16 +11,17 @@
#include "js/GCAPI.h"
#include "mozilla/Atomics.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabParent.h"
+#include "mozilla/HangAnnotations.h"
#include "mozilla/Monitor.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/Preferences.h"
#include "mozilla/Unused.h"
#include "nsIFrameLoader.h"
#include "nsIHangReport.h"
#include "nsITabParent.h"
@@ -67,16 +68,17 @@ using namespace mozilla::dom;
*/
namespace {
/* Child process objects */
class HangMonitorChild
: public PProcessHangMonitorChild
+ , public mozilla::HangMonitor::Annotator
{
public:
explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
virtual ~HangMonitorChild();
void Open(Transport* aTransport, ProcessId aOtherPid,
MessageLoop* aIOLoop);
@@ -109,29 +111,33 @@ class HangMonitorChild
static HangMonitorChild* Get() { return sInstance; }
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
private:
void ShutdownOnThread();
+ virtual void
+ AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
+
static Atomic<HangMonitorChild*> sInstance;
const RefPtr<ProcessHangMonitor> mHangMonitor;
Monitor mMonitor;
// Main thread-only.
bool mSentReport;
// These fields must be accessed with mMonitor held.
bool mTerminateScript;
bool mStartDebugger;
bool mFinishedStartingDebugger;
- bool mForcePaint;
+ bool mForcePaintRequested;
+ bool mForcePaintInProgress;
TabId mForcePaintTab;
MOZ_INIT_OUTSIDE_CTOR uint64_t mForcePaintEpoch;
JSContext* mContext;
bool mShutdownDone;
// This field is only accessed on the hang thread.
bool mIPCOpen;
};
@@ -266,17 +272,18 @@ private:
HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
: mHangMonitor(aMonitor),
mMonitor("HangMonitorChild lock"),
mSentReport(false),
mTerminateScript(false),
mStartDebugger(false),
mFinishedStartingDebugger(false),
- mForcePaint(false),
+ mForcePaintRequested(false),
+ mForcePaintInProgress(false),
mShutdownDone(false),
mIPCOpen(true)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
mContext = danger::GetJSContext();
}
HangMonitorChild::~HangMonitorChild()
@@ -286,60 +293,77 @@ HangMonitorChild::~HangMonitorChild()
sInstance = nullptr;
}
void
HangMonitorChild::InterruptCallback()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
- bool forcePaint;
+ bool forcePaintRequested;
TabId forcePaintTab;
uint64_t forcePaintEpoch;
{
MonitorAutoLock lock(mMonitor);
- forcePaint = mForcePaint;
+ forcePaintRequested = mForcePaintRequested;
forcePaintTab = mForcePaintTab;
forcePaintEpoch = mForcePaintEpoch;
- mForcePaint = false;
+ mForcePaintRequested = false;
}
- if (forcePaint) {
+ if (forcePaintRequested) {
RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
if (tabChild) {
JS::AutoAssertOnGC nogc(mContext);
JS::AutoAssertOnBarrier nobarrier(mContext);
tabChild->ForcePaint(forcePaintEpoch);
}
+
+ MonitorAutoLock lock(mMonitor);
+ mForcePaintInProgress = false;
}
}
void
HangMonitorChild::Shutdown()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
+ mozilla::HangMonitor::UnregisterAnnotator(*this);
+
MonitorAutoLock lock(mMonitor);
while (!mShutdownDone) {
mMonitor.Wait();
}
}
void
HangMonitorChild::ShutdownOnThread()
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
MonitorAutoLock lock(mMonitor);
mShutdownDone = true;
mMonitor.Notify();
}
+/**
+ * This function is always called by the HangMonitor thread.
+ */
+void
+HangMonitorChild::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
+{
+ MonitorAutoLock lock(mMonitor);
+ if (mForcePaintInProgress) {
+ aAnnotations.AddAnnotation(NS_LITERAL_STRING("ForcePaintInProgress"), true);
+ }
+}
+
void
HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
mIPCOpen = false;
// We use a task here to ensure that IPDL is finished with this
@@ -379,17 +403,18 @@ HangMonitorChild::RecvEndStartingDebugge
bool
HangMonitorChild::RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
{
MonitorAutoLock lock(mMonitor);
- mForcePaint = true;
+ mForcePaintRequested = true;
+ mForcePaintInProgress = true;
mForcePaintTab = aTabId;
mForcePaintEpoch = aLayerObserverEpoch;
}
JS_RequestInterruptCallback(mContext);
JS::RequestGCInterruptCallback(mContext);
return true;
@@ -1189,16 +1214,18 @@ mozilla::CreateHangMonitorChild(mozilla:
JSContext* cx = danger::GetJSContext();
JS_AddInterruptCallback(cx, InterruptCallback);
JS::AddGCInterruptCallback(cx, InterruptCallback);
ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
HangMonitorChild* child = new HangMonitorChild(monitor);
+ mozilla::HangMonitor::RegisterAnnotator(*child);
+
monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod
<mozilla::ipc::Transport*,
base::ProcessId,
MessageLoop*>(child,
&HangMonitorChild::Open,
aTransport, aOtherPid,
XRE_GetIOMessageLoop()));