diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 7d57e7d5fac..39f66d377ca 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -7,6 +7,7 @@ #include "mozilla/LinkedList.h" #include "mozilla/Monitor.h" #include "mozilla/StaticPtr.h" +#include "mozilla/ThreadHangStats.h" #include "mozilla/ThreadLocal.h" #include "prinrval.h" @@ -103,8 +104,6 @@ public: if (!sTlsKey.init()) {} } - // Name of the thread - const nsAutoCString mThreadName; // Hang timeout in ticks const PRIntervalTime mTimeout; // PermaHang timeout in ticks @@ -117,6 +116,8 @@ public: bool mHanging; // Is the thread in a waiting state bool mWaiting; + // Statistics for telemetry + Telemetry::ThreadHangStats mStats; BackgroundHangThread(const char* aName, uint32_t aTimeoutMs, @@ -292,13 +293,13 @@ BackgroundHangThread::BackgroundHangThread(const char* aName, uint32_t aMaxTimeoutMs) : mManager(BackgroundHangManager::sInstance) , mThreadID(PR_GetCurrentThread()) - , mThreadName(aName) , mTimeout(PR_MillisecondsToInterval(aTimeoutMs)) , mMaxTimeout(PR_MillisecondsToInterval(aMaxTimeoutMs)) , mInterval(mManager->mIntervalNow) , mHangStart(mInterval) , mHanging(false) , mWaiting(true) + , mStats(aName) { if (sTlsKey.initialized()) { sTlsKey.set(this); @@ -440,4 +441,25 @@ BackgroundHangMonitor::NotifyWait() mThread->NotifyWait(); } + +/* Because we are iterating through the BackgroundHangThread linked list, + we need to take a lock. Using MonitorAutoLock as a base class makes + sure all of that is taken care of for us. */ +BackgroundHangMonitor::ThreadHangStatsIterator::ThreadHangStatsIterator() + : MonitorAutoLock(BackgroundHangManager::sInstance->mLock) + , mThread(BackgroundHangManager::sInstance->mHangThreads.getFirst()) +{ +} + +Telemetry::ThreadHangStats* +BackgroundHangMonitor::ThreadHangStatsIterator::GetNext() +{ + if (!mThread) { + return nullptr; + } + Telemetry::ThreadHangStats* stats = &mThread->mStats; + mThread = mThread->getNext(); + return stats; +} + } // namespace mozilla diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index 24367978acc..d735d7de380 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -7,11 +7,16 @@ #define mozilla_BackgroundHangMonitor_h #include "mozilla/RefPtr.h" +#include "mozilla/Monitor.h" #include namespace mozilla { +namespace Telemetry { +class ThreadHangStats; +}; + class BackgroundHangThread; /** @@ -101,6 +106,44 @@ private: RefPtr mThread; public: + /** + * ThreadHangStatsIterator is used to iterate through the ThreadHangStats + * associated with each active monitored thread. Because of an internal + * lock while this object is alive, a thread must use only one instance + * of this class at a time and must iterate through the list as fast as + * possible. The following example shows using the iterator: + * + * { + * // Scope the iter variable so it's destroyed as soon as we're done + * BackgroundHangMonitor::ThreadHangStatsIterator iter; + * for (ThreadHangStats* histogram = iter.GetNext(); + * histogram; histogram = iter.GetNext()) { + * // Process histogram + * } + * } + */ + class ThreadHangStatsIterator : public MonitorAutoLock + { + private: + BackgroundHangThread* mThread; + + ThreadHangStatsIterator(const ThreadHangStatsIterator&); + ThreadHangStatsIterator& operator=(const ThreadHangStatsIterator&); + + public: + /** + * Create an ThreadHangStatsIterator instance and take the internal lock. + * Internal lock is released on destruction. + */ + ThreadHangStatsIterator(); + + /** + * Get the next item in the list; the first call returns the first item. + * Returns nullptr at the end of the list. + */ + Telemetry::ThreadHangStats* GetNext(); + }; + /** * Enable hang monitoring. * Must return before using BackgroundHangMonitor.