gecko-dev/xpcom/threads/HangAnnotations.cpp
Michael Layzell 65ece3dba5 Bug 1380081 - Part 11: Simplify the HangAnnotations abstraction, r=froydnj
HangAnnotations was very complex, required a separate allocation, and used this
unfortunate virtual interface implementation which made it harder to do
interesting things with it (such as serialize it over IPC).

This new implementation is much simpler and more concrete, making
HangAnnotations simply be a nsTArray<Annotation>. This also simplifies some of
the IPC code which was added in part 7.

MozReview-Commit-ID: EzaaxdHpW1t
2017-08-15 16:35:46 -04:00

176 lines
4.1 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/HangAnnotations.h"
#include <vector>
#include "MainThreadUtils.h"
#include "mozilla/DebugOnly.h"
#include "nsXULAppAPI.h"
#include "mozilla/BackgroundHangMonitor.h"
namespace mozilla {
namespace HangMonitor {
// Chrome hang annotators. This can go away once BHR has completely replaced
// ChromeHangs.
static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators;
void
HangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
{
nsAutoString dataString;
dataString.AppendInt(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
{
nsAutoString dataString;
dataString.AppendFloat(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
{
AppendElement(Annotation(aName, aData));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
{
NS_ConvertUTF8toUTF16 dataString(aData);
AppendElement(Annotation(aName, dataString));
}
void
HangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
{
if (aData) {
AppendElement(Annotation(aName, NS_LITERAL_STRING("true")));
} else {
AppendElement(Annotation(aName, NS_LITERAL_STRING("false")));
}
}
namespace Observer {
Annotators::Annotators()
: mMutex("HangMonitor::Annotators::mMutex")
{
MOZ_COUNT_CTOR(Annotators);
}
Annotators::~Annotators()
{
MOZ_ASSERT(mAnnotators.empty());
MOZ_COUNT_DTOR(Annotators);
}
bool
Annotators::Register(Annotator& aAnnotator)
{
MutexAutoLock lock(mMutex);
auto result = mAnnotators.insert(&aAnnotator);
return result.second;
}
bool
Annotators::Unregister(Annotator& aAnnotator)
{
MutexAutoLock lock(mMutex);
DebugOnly<std::set<Annotator*>::size_type> numErased;
numErased = mAnnotators.erase(&aAnnotator);
MOZ_ASSERT(numErased == 1);
return mAnnotators.empty();
}
HangAnnotations
Annotators::GatherAnnotations()
{
HangAnnotations annotations;
{ // Scope for lock
MutexAutoLock lock(mMutex);
for (std::set<Annotator*>::iterator i = mAnnotators.begin(),
e = mAnnotators.end();
i != e; ++i) {
(*i)->AnnotateHang(annotations);
}
}
return annotations;
}
} // namespace Observer
void
RegisterAnnotator(Annotator& aAnnotator)
{
BackgroundHangMonitor::RegisterAnnotator(aAnnotator);
// We still register annotators for ChromeHangs
if (NS_IsMainThread() &&
GeckoProcessType_Default == XRE_GetProcessType()) {
if (!gChromehangAnnotators) {
gChromehangAnnotators = new Observer::Annotators();
}
gChromehangAnnotators->Register(aAnnotator);
}
}
void
UnregisterAnnotator(Annotator& aAnnotator)
{
BackgroundHangMonitor::UnregisterAnnotator(aAnnotator);
// We still register annotators for ChromeHangs
if (NS_IsMainThread() &&
GeckoProcessType_Default == XRE_GetProcessType()) {
if (gChromehangAnnotators->Unregister(aAnnotator)) {
gChromehangAnnotators = nullptr;
}
}
}
HangAnnotations
ChromeHangAnnotatorCallout()
{
if (!gChromehangAnnotators) {
return HangAnnotations();
}
return gChromehangAnnotators->GatherAnnotations();
}
} // namespace HangMonitor
} // namespace mozilla
namespace IPC {
using mozilla::HangMonitor::Annotation;
void
ParamTraits<Annotation>::Write(Message* aMsg, const Annotation& aParam)
{
WriteParam(aMsg, aParam.mName);
WriteParam(aMsg, aParam.mValue);
}
bool
ParamTraits<Annotation>::Read(const Message* aMsg,
PickleIterator* aIter,
Annotation* aResult)
{
if (!ReadParam(aMsg, aIter, &aResult->mName)) {
return false;
}
if (!ReadParam(aMsg, aIter, &aResult->mValue)) {
return false;
}
return true;
}
} // namespace IPC