From f2fa59191293c5e4b1cba95a10d78fe063aaa045 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Wed, 19 Oct 2016 14:32:43 -0400 Subject: [PATCH] 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 --- xpcom/threads/BackgroundHangMonitor.cpp | 52 +++++++++++++++++++------ xpcom/threads/BackgroundHangMonitor.h | 16 +++++++- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 8f7d304db4b4..028b5b04046c 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -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 } diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index d8390b161ccd..698cf2305ebb 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -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