diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 9e576db308b..2516211d683 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -2911,21 +2911,20 @@ TelemetryImpl::GetThreadHangStats(JSContext* cx, JS::MutableHandle re } size_t threadIndex = 0; -#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR - /* First add active threads; we need to hold |iter| (and its lock) - throughout this method to avoid a race condition where a thread can - be recorded twice if the thread is destroyed while this method is - running */ - BackgroundHangMonitor::ThreadHangStatsIterator iter; - for (Telemetry::ThreadHangStats* histogram = iter.GetNext(); - histogram; histogram = iter.GetNext()) { - JS::RootedObject obj(cx, - CreateJSThreadHangStats(cx, *histogram)); - if (!JS_DefineElement(cx, retObj, threadIndex++, obj, JSPROP_ENUMERATE)) { - return NS_ERROR_FAILURE; + if (!BackgroundHangMonitor::IsDisabled()) { + /* First add active threads; we need to hold |iter| (and its lock) + throughout this method to avoid a race condition where a thread can + be recorded twice if the thread is destroyed while this method is + running */ + BackgroundHangMonitor::ThreadHangStatsIterator iter; + for (Telemetry::ThreadHangStats* histogram = iter.GetNext(); + histogram; histogram = iter.GetNext()) { + JS::RootedObject obj(cx, CreateJSThreadHangStats(cx, *histogram)); + if (!JS_DefineElement(cx, retObj, threadIndex++, obj, JSPROP_ENUMERATE)) { + return NS_ERROR_FAILURE; + } } } -#endif // Add saved threads next MutexAutoLock autoLock(mThreadHangStatsMutex); diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index c09ff745d8a..d4fef4b7387 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -9,6 +9,7 @@ #include "mozilla/LinkedList.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" +#include "mozilla/Preferences.h" #include "mozilla/StaticPtr.h" #include "mozilla/Telemetry.h" #include "mozilla/ThreadHangStats.h" @@ -20,16 +21,23 @@ #include "prinrval.h" #include "prthread.h" #include "ThreadStackHelper.h" +#include "nsIObserverService.h" +#include "nsIObserver.h" +#include "mozilla/Services.h" +#include "nsXULAppAPI.h" #include +// Activate BHR only for one every BHR_BETA_MOD users. +#define BHR_BETA_MOD 100; + namespace mozilla { /** * BackgroundHangManager is the global object that * manages all instances of BackgroundHangThread. */ -class BackgroundHangManager +class BackgroundHangManager : public nsIObserver { private: // Background hang monitor thread function @@ -61,9 +69,11 @@ private: void RunMonitorThread(); public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundHangManager) + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIOBSERVER static StaticRefPtr sInstance; static bool sProhibited; + static bool sDisabled; // Lock for access to members of this class Monitor mLock; @@ -90,9 +100,23 @@ public: BackgroundHangManager(); private: - ~BackgroundHangManager(); + virtual ~BackgroundHangManager(); }; +NS_IMPL_ISUPPORTS(BackgroundHangManager, nsIObserver) + +NS_IMETHODIMP +BackgroundHangManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { + NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED); + BackgroundHangMonitor::DisableOnBeta(); + + nsCOMPtr observerService = mozilla::services::GetObserverService(); + MOZ_ASSERT(observerService); + observerService->RemoveObserver(this, "profile-after-change"); + + return NS_OK; +} + /** * BackgroundHangThread is a per-thread object that is used * by all instances of BackgroundHangMonitor to monitor hangs. @@ -162,6 +186,7 @@ public: StaticRefPtr BackgroundHangManager::sInstance; bool BackgroundHangManager::sProhibited = false; +bool BackgroundHangManager::sDisabled = false; ThreadLocal BackgroundHangThread::sTlsKey; @@ -421,7 +446,7 @@ BackgroundHangThread::FindThread() { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR if (BackgroundHangManager::sInstance == nullptr) { - MOZ_ASSERT(BackgroundHangManager::sProhibited, + MOZ_ASSERT(BackgroundHangManager::sProhibited || BackgroundHangManager::sDisabled, "BackgroundHandleManager is not initialized"); return nullptr; } @@ -450,6 +475,38 @@ BackgroundHangThread::FindThread() return nullptr; } +bool +BackgroundHangMonitor::ShouldDisableOnBeta(const nsCString &clientID) { + MOZ_ASSERT(clientID.Length() == 36, "clientID is invalid"); + const char *suffix = clientID.get() + clientID.Length() - 4; + return strtol(suffix, NULL, 16) % BHR_BETA_MOD; +} + +bool +BackgroundHangMonitor::IsDisabled() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + return BackgroundHangManager::sDisabled; +#else + return true; +#endif +} + +bool +BackgroundHangMonitor::DisableOnBeta() { + nsAdoptingCString clientID = Preferences::GetCString("toolkit.telemetry.cachedClientID"); + bool telemetryEnabled = Preferences::GetBool("toolkit.telemetry.enabled"); + + if (!telemetryEnabled || !clientID || BackgroundHangMonitor::ShouldDisableOnBeta(clientID)) { + if (XRE_IsParentProcess()) { + BackgroundHangMonitor::Shutdown(); + } else { + BackgroundHangManager::sDisabled = true; + } + return true; + } + + return false; +} void BackgroundHangMonitor::Startup() @@ -457,6 +514,23 @@ BackgroundHangMonitor::Startup() #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR MOZ_ASSERT(!BackgroundHangManager::sProhibited, "Prohibited"); MOZ_ASSERT(!BackgroundHangManager::sInstance, "Already initialized"); + + if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "beta")) { + if (XRE_IsParentProcess()) { // cached ClientID hasn't been read yet + ThreadStackHelper::Startup(); + BackgroundHangThread::Startup(); + BackgroundHangManager::sInstance = new BackgroundHangManager(); + + nsCOMPtr observerService = mozilla::services::GetObserverService(); + MOZ_ASSERT(observerService); + + observerService->AddObserver(BackgroundHangManager::sInstance, "profile-after-change", false); + return; + } else if(DisableOnBeta()){ + return; + } + } + ThreadStackHelper::Startup(); BackgroundHangThread::Startup(); BackgroundHangManager::sInstance = new BackgroundHangManager(); @@ -467,6 +541,11 @@ void BackgroundHangMonitor::Shutdown() { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + if (BackgroundHangManager::sDisabled) { + MOZ_ASSERT(!BackgroundHangManager::sInstance, "Initialized"); + return; + } + MOZ_ASSERT(!BackgroundHangManager::sProhibited, "Prohibited"); MOZ_ASSERT(BackgroundHangManager::sInstance, "Not initialized"); /* Scope our lock inside Shutdown() because the sInstance object can @@ -475,6 +554,7 @@ BackgroundHangMonitor::Shutdown() BackgroundHangManager::sInstance->Shutdown(); BackgroundHangManager::sInstance = nullptr; ThreadStackHelper::Shutdown(); + BackgroundHangManager::sDisabled = true; #endif } @@ -484,7 +564,7 @@ BackgroundHangMonitor::BackgroundHangMonitor(const char* aName, : mThread(BackgroundHangThread::FindThread()) { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR - if (!BackgroundHangManager::sProhibited && !mThread) { + if (!BackgroundHangManager::sDisabled && !BackgroundHangManager::sProhibited && !mThread) { // If sProhibit is true, mThread would be null, and no monitoring. mThread = new BackgroundHangThread(aName, aTimeoutMs, aMaxTimeoutMs); } @@ -495,6 +575,10 @@ BackgroundHangMonitor::BackgroundHangMonitor() : mThread(BackgroundHangThread::FindThread()) { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + if (BackgroundHangManager::sDisabled) { + return; + } + MOZ_ASSERT(!BackgroundHangManager::sProhibited || mThread, "This thread is not initialized for hang monitoring"); #endif @@ -509,7 +593,8 @@ BackgroundHangMonitor::NotifyActivity() { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR if (mThread == nullptr) { - MOZ_ASSERT(BackgroundHangManager::sProhibited, + MOZ_ASSERT(BackgroundHangManager::sProhibited || + BackgroundHangManager::sDisabled, "This thread is not initialized for hang monitoring"); return; } @@ -525,7 +610,8 @@ BackgroundHangMonitor::NotifyWait() { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR if (mThread == nullptr) { - MOZ_ASSERT(BackgroundHangManager::sProhibited, + MOZ_ASSERT(BackgroundHangManager::sProhibited || + BackgroundHangManager::sDisabled, "This thread is not initialized for hang monitoring"); return; } @@ -567,7 +653,9 @@ BackgroundHangMonitor::ThreadHangStatsIterator::ThreadHangStatsIterator() nullptr) { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR - MOZ_ASSERT(BackgroundHangManager::sInstance || BackgroundHangManager::sProhibited, + MOZ_ASSERT(BackgroundHangManager::sInstance || + BackgroundHangManager::sProhibited || + BackgroundHangManager::sDisabled, "Inconsistent state"); #endif } diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index 059fb0a08ff..333ae086b70 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -10,6 +10,8 @@ #include "mozilla/RefPtr.h" #include "mozilla/Monitor.h" +#include "nsString.h" + #include namespace mozilla { @@ -18,14 +20,8 @@ namespace Telemetry { class ThreadHangStats; }; -// Disabled for Beta/Release builds because of bug 965392. -// Disabled for debug builds because of bug 979069. -#if !defined(RELEASE_BUILD) && !defined(DEBUG) -// Undefine to disable background hang monitor -#define MOZ_ENABLE_BACKGROUND_HANG_MONITOR -#endif - class BackgroundHangThread; +class BackgroundHangManager; /** * The background hang monitor is responsible for detecting and reporting @@ -113,8 +109,13 @@ class BackgroundHangThread; class BackgroundHangMonitor { private: + friend BackgroundHangManager; + RefPtr mThread; + static bool ShouldDisableOnBeta(const nsCString &); + static bool DisableOnBeta(); + public: static const uint32_t kNoTimeout = 0; @@ -168,6 +169,11 @@ public: */ static void Shutdown(); + /** + * Returns true if BHR is disabled. + */ + static bool IsDisabled(); + /** * Start monitoring hangs for the current thread. * diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index 32cd6124596..05aa656c2ed 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -59,6 +59,11 @@ LOCAL_INCLUDES += [ '/tools/profiler', ] +# BHR disabled for Release builds because of bug 965392. +# BHR disabled for debug builds because of bug 979069. +if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('release') and not CONFIG['DEBUG']: + DEFINES['MOZ_ENABLE_BACKGROUND_HANG_MONITOR'] = 1 + FAIL_ON_WARNINGS = True FINAL_LIBRARY = 'xul'