Bug 1310880 - Allow a BackgroundHangMonitor to have its own private BackgroundHangThread. r=jchen

MozReview-Commit-ID: L32E19FVhv

--HG--
extra : rebase_source : ad279f8a04e2e33a8b37e15674263aa7a1a0efbf
extra : histedit_source : 9f085995ec8d39014a45ab06fb366fb52eb57c6c
This commit is contained in:
Mike Conley 2016-10-19 14:32:43 -04:00
Родитель 7481809d32
Коммит f2fa591912
2 изменённых файлов: 55 добавлений и 13 удалений

Просмотреть файл

@ -141,14 +141,24 @@ private:
// Unique thread ID for identification
const PRThread* mThreadID;
void Update();
public:
NS_INLINE_DECL_REFCOUNTING(BackgroundHangThread)
/**
* Returns the BackgroundHangThread associated with the
* running thread. Note that this will not find private
* BackgroundHangThread threads.
*
* @return BackgroundHangThread*, or nullptr if no thread
* is found.
*/
static BackgroundHangThread* FindThread();
static void Startup()
{
/* We can tolerate init() failing. */
(void)!sTlsKey.init();
sTlsKeyInitialized = sTlsKey.init();
}
// Hang timeout in ticks
@ -163,6 +173,8 @@ public:
bool mHanging;
// Is the thread in a waiting state
bool mWaiting;
// Is the thread dedicated to a single BackgroundHangMonitor
BackgroundHangMonitor::ThreadType mThreadType;
// Platform-specific helper to get hang stacks
ThreadStackHelper mStackHelper;
// Stack of current hang
@ -176,20 +188,32 @@ public:
BackgroundHangThread(const char* aName,
uint32_t aTimeoutMs,
uint32_t aMaxTimeoutMs);
uint32_t aMaxTimeoutMs,
BackgroundHangMonitor::ThreadType aThreadType = BackgroundHangMonitor::THREAD_SHARED);
// Report a hang; aManager->mLock IS locked
Telemetry::HangHistogram& ReportHang(PRIntervalTime aHangTime);
// Report a permanent hang; aManager->mLock IS locked
void ReportPermaHang();
// Called by BackgroundHangMonitor::NotifyActivity
void NotifyActivity();
void NotifyActivity()
{
MonitorAutoLock autoLock(mManager->mLock);
Update();
}
// Called by BackgroundHangMonitor::NotifyWait
void NotifyWait()
{
NotifyActivity();
MonitorAutoLock autoLock(mManager->mLock);
Update();
mWaiting = true;
}
// Returns true if this thread is (or might be) shared between other
// BackgroundHangMonitors for the monitored thread.
bool IsShared() {
return mThreadType == BackgroundHangMonitor::THREAD_SHARED;
}
};
@ -347,7 +371,8 @@ BackgroundHangManager::RunMonitorThread()
BackgroundHangThread::BackgroundHangThread(const char* aName,
uint32_t aTimeoutMs,
uint32_t aMaxTimeoutMs)
uint32_t aMaxTimeoutMs,
BackgroundHangMonitor::ThreadType aThreadType)
: mManager(BackgroundHangManager::sInstance)
, mThreadID(PR_GetCurrentThread())
, mTimeout(aTimeoutMs == BackgroundHangMonitor::kNoTimeout
@ -360,9 +385,10 @@ BackgroundHangThread::BackgroundHangThread(const char* aName,
, mHangStart(mInterval)
, mHanging(false)
, mWaiting(true)
, mThreadType(aThreadType)
, mStats(aName)
{
if (sTlsKeyInitialized) {
if (sTlsKeyInitialized && IsShared()) {
sTlsKey.set(this);
}
// Lock here because LinkedList is not thread-safe
@ -383,7 +409,7 @@ BackgroundHangThread::~BackgroundHangThread()
autoLock.Notify();
// We no longer have a thread
if (sTlsKeyInitialized) {
if (sTlsKeyInitialized && IsShared()) {
sTlsKey.set(nullptr);
}
@ -452,7 +478,7 @@ BackgroundHangThread::ReportPermaHang()
}
MOZ_ALWAYS_INLINE void
BackgroundHangThread::NotifyActivity()
BackgroundHangThread::Update()
{
PRIntervalTime intervalNow = mManager->mIntervalNow;
if (mWaiting) {
@ -495,7 +521,7 @@ BackgroundHangThread::FindThread()
MonitorAutoLock autoLock(manager->mLock);
for (BackgroundHangThread* thread = manager->mHangThreads.getFirst();
thread; thread = thread->getNext()) {
if (thread->mThreadID == threadID) {
if (thread->mThreadID == threadID && thread->IsShared()) {
return thread;
}
}
@ -587,12 +613,14 @@ BackgroundHangMonitor::Shutdown()
BackgroundHangMonitor::BackgroundHangMonitor(const char* aName,
uint32_t aTimeoutMs,
uint32_t aMaxTimeoutMs)
: mThread(BackgroundHangThread::FindThread())
uint32_t aMaxTimeoutMs,
ThreadType aThreadType)
: mThread(aThreadType == THREAD_SHARED ? BackgroundHangThread::FindThread() : nullptr)
{
#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
if (!BackgroundHangManager::sDisabled && !mThread) {
mThread = new BackgroundHangThread(aName, aTimeoutMs, aMaxTimeoutMs);
mThread = new BackgroundHangThread(aName, aTimeoutMs, aMaxTimeoutMs,
aThreadType);
}
#endif
}

Просмотреть файл

@ -116,6 +116,16 @@ private:
public:
static const uint32_t kNoTimeout = 0;
enum ThreadType {
// For a new BackgroundHangMonitor for thread T, only create a new
// monitoring thread for T if one doesn't already exist. If one does,
// share that pre-existing monitoring thread.
THREAD_SHARED,
// For a new BackgroundHangMonitor for thread T, create a new
// monitoring thread for T even if there are other, pre-existing
// monitoring threads for T.
THREAD_PRIVATE
};
/**
* ThreadHangStatsIterator is used to iterate through the ThreadHangStats
@ -180,10 +190,14 @@ public:
* activity before registering a hang
* @param aMaxTimeoutMs Amount of time in milliseconds without
* activity before registering a permanent hang
* @param aThreadType
* The ThreadType type of monitoring thread that should be created
* for this monitor. See the documentation for ThreadType.
*/
BackgroundHangMonitor(const char* aName,
uint32_t aTimeoutMs,
uint32_t aMaxTimeoutMs);
uint32_t aMaxTimeoutMs,
ThreadType aThreadType = THREAD_SHARED);
/**
* Monitor hangs using an existing monitor