From c0da861aa4812a76a2ada20bef2c5d33ce31b7e1 Mon Sep 17 00:00:00 2001 From: "Patrick Wang (Chih-Kai Wang)" Date: Mon, 24 Nov 2014 15:21:52 +0800 Subject: [PATCH] Bug 970307: Part 1: Report status of each thread to find when all the threads are idle. r=nfroyd --- dom/indexedDB/TransactionThreadPool.cpp | 27 +++ dom/wifi/WifiProxyService.cpp | 3 + dom/workers/WorkerPrivate.cpp | 12 + .../base/src/nsSocketTransportService2.cpp | 1 + widget/gonk/GonkMemoryPressureMonitoring.cpp | 2 + xpcom/glue/nsThreadUtils.cpp | 8 + xpcom/glue/nsThreadUtils.h | 15 ++ xpcom/threads/TimerThread.cpp | 1 + xpcom/threads/nsThread.cpp | 49 +++- xpcom/threads/nsThread.h | 15 ++ xpcom/threads/nsThreadManager.cpp | 212 ++++++++++++++++++ xpcom/threads/nsThreadManager.h | 38 ++++ xpcom/threads/nsThreadPool.cpp | 7 +- xpcom/threads/nsTimerImpl.cpp | 7 + 14 files changed, 394 insertions(+), 3 deletions(-) diff --git a/dom/indexedDB/TransactionThreadPool.cpp b/dom/indexedDB/TransactionThreadPool.cpp index d0e68990e958..385f4dd50687 100644 --- a/dom/indexedDB/TransactionThreadPool.cpp +++ b/dom/indexedDB/TransactionThreadPool.cpp @@ -19,6 +19,7 @@ #include "nsServiceManagerUtils.h" #include "nsXPCOMCIDInternal.h" #include "ProfilerHelpers.h" +#include "nsThread.h" namespace mozilla { namespace dom { @@ -172,6 +173,10 @@ private: ~TransactionQueue() { } +#ifdef MOZ_NUWA_PROCESS + nsThread* mThread; +#endif + NS_DECL_NSIRUNNABLE }; @@ -791,6 +796,9 @@ TransactionQueue::TransactionQueue(TransactionThreadPool* aThreadPool, mObjectStoreNames(aObjectStoreNames), mMode(aMode), mShouldFinish(false) +#ifdef MOZ_NUWA_PROCESS +, mThread(nullptr) +#endif { MOZ_ASSERT(aThreadPool); aThreadPool->AssertIsOnOwningThread(); @@ -816,6 +824,12 @@ TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable) mQueue.AppendElement(aRunnable); +#ifdef MOZ_NUWA_PROCESS + if (mThread) { + mThread->SetWorking(); + } +#endif + mMonitor.Notify(); } @@ -849,6 +863,12 @@ TransactionThreadPool::TransactionQueue::Run() nsAutoTArray, 10> queue; nsRefPtr finishCallback; bool shouldFinish = false; +#ifdef MOZ_NUWA_PROCESS + mThread = static_cast(NS_GetCurrentThread()); + // Set ourself as working thread. We can reset later if we found + // our queue is empty. + mThread->SetWorking(); +#endif do { NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!"); @@ -856,6 +876,9 @@ TransactionThreadPool::TransactionQueue::Run() { MonitorAutoLock lock(mMonitor); while (!mShouldFinish && mQueue.IsEmpty()) { +#ifdef MOZ_NUWA_PROCESS + mThread->SetIdle(); +#endif if (NS_FAILED(mMonitor.Wait())) { NS_ERROR("Failed to wait!"); } @@ -888,6 +911,10 @@ TransactionThreadPool::TransactionQueue::Run() } } while (!shouldFinish); +#ifdef MOZ_NUWA_PROCESS + mThread = nullptr; +#endif + #ifdef DEBUG if (kDEBUGThreadSleepMS) { MOZ_ALWAYS_TRUE( diff --git a/dom/wifi/WifiProxyService.cpp b/dom/wifi/WifiProxyService.cpp index 5770c96811da..7e026db2c604 100644 --- a/dom/wifi/WifiProxyService.cpp +++ b/dom/wifi/WifiProxyService.cpp @@ -65,6 +65,9 @@ public: NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); +#ifdef MOZ_NUWA_PROCESS + NS_SetIgnoreStatusOfCurrentThread(); +#endif nsAutoString event; gWpaSupplicant->WaitForEvent(event, mInterface); if (!event.IsEmpty()) { diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 2ff28cebc1c8..45e4962b3125 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -65,6 +65,7 @@ #include "nsPrintfCString.h" #include "nsProxyRelease.h" #include "nsSandboxFlags.h" +#include "nsThread.h" #include "xpcpublic.h" #ifdef ANDROID @@ -4166,6 +4167,17 @@ WorkerPrivate::DoRunLoop(JSContext* aCx) { MutexAutoLock lock(mMutex); +#ifdef MOZ_NUWA_PROCESS + { + nsThread *thr = static_cast(NS_GetCurrentThread()); + ReentrantMonitorAutoEnter mon(thr->ThreadStatusMonitor()); + if (mControlQueue.IsEmpty() && + !(normalRunnablesPending = NS_HasPendingEvents(mThread))) { + thr->SetIdle(); + } + } +#endif // MOZ_NUWA_PROCESS + while (mControlQueue.IsEmpty() && !(normalRunnablesPending = NS_HasPendingEvents(mThread))) { WaitForWorkerEvents(); diff --git a/netwerk/base/src/nsSocketTransportService2.cpp b/netwerk/base/src/nsSocketTransportService2.cpp index c664bca538af..a17fc7cb3064 100644 --- a/netwerk/base/src/nsSocketTransportService2.cpp +++ b/netwerk/base/src/nsSocketTransportService2.cpp @@ -701,6 +701,7 @@ nsSocketTransportService::Run() "NuwaMarkCurrentThread is undefined!"); NuwaMarkCurrentThread(nullptr, nullptr); } + NS_SetIgnoreStatusOfCurrentThread(); #endif SOCKET_LOG(("STS thread init\n")); diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp index 949f36c5bf16..ac018c046a70 100644 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp @@ -127,6 +127,8 @@ public: } #endif + NS_SetIgnoreStatusOfCurrentThread(); + int lowMemFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active", O_RDONLY | O_CLOEXEC); NS_ENSURE_STATE(lowMemFd != -1); diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index c6d43dc09be8..ce914d7d15c7 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -375,3 +375,11 @@ nsAutoLowPriorityIO::~nsAutoLowPriorityIO() #endif } +#ifdef MOZ_NUWA_PROCESS +#ifdef MOZILLA_INTERNAL_API +void +NS_SetIgnoreStatusOfCurrentThread() { + nsThreadManager::get()->SetIgnoreThreadStatus(); +} +#endif // MOZILLA_INTERNAL_API +#endif // MOZ_NUWA_PROCESS diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index 47c7eaee4fe6..93c4b31ff220 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -565,4 +565,19 @@ private: void NS_SetMainThread(); +/** + * Helpers for thread to report their status when compiled with Nuwa. + */ +#ifdef MOZILLA_INTERNAL_API +#ifdef MOZ_NUWA_PROCESS +extern void +NS_SetIgnoreStatusOfCurrentThread(); +#else // MOZ_NUWA_PROCESS +inline void +NS_SetIgnoreStatusOfCurrentThread() +{ +} +#endif // MOZ_NUWA_PROCESS +#endif // MOZILLA_INTERNAL_API + #endif // nsThreadUtils_h__ diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index 7689c80e3bfb..39281be80490 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -207,6 +207,7 @@ TimerThread::Run() } #endif + NS_SetIgnoreStatusOfCurrentThread(); MonitorAutoLock lock(mMonitor); // We need to know how many microseconds give a positive PRIntervalTime. This diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index d660d981887e..796d8cbe7cca 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -13,7 +13,6 @@ #undef LOG #endif -#include "mozilla/ReentrantMonitor.h" #include "nsMemoryPressure.h" #include "nsThreadManager.h" #include "nsIClassInfoImpl.h" @@ -329,6 +328,10 @@ nsThread::ThreadFunc(void* aArg) // Inform the ThreadManager nsThreadManager::get()->RegisterCurrentThread(self); +#ifdef MOZ_NUWA_PROCESS + self->mThreadStatusInfo = + static_cast(nsThreadManager::get()->GetCurrentThreadStatusInfo()); +#endif mozilla::IOInterposer::RegisterCurrentThread(); @@ -434,6 +437,10 @@ nsThread::nsThread(MainThreadFlag aMainThread, uint32_t aStackSize) , mShutdownRequired(false) , mEventsAreDoomed(false) , mIsMainThread(aMainThread) +#ifdef MOZ_NUWA_PROCESS + , mThreadStatusMonitor("nsThread.mThreadStatusLock") + , mThreadStatusInfo(nullptr) +#endif { } @@ -481,6 +488,11 @@ nsThread::InitCurrentThread() SetupCurrentThreadForChaosMode(); nsThreadManager::get()->RegisterCurrentThread(this); +#ifdef MOZ_NUWA_PROCESS + mThreadStatusInfo = + static_cast(nsThreadManager::get()->GetCurrentThreadStatusInfo()); +#endif + return NS_OK; } @@ -496,7 +508,15 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget) NS_WARNING("An event was posted to a thread that will never run it (rejected)"); return NS_ERROR_UNEXPECTED; } - queue->PutEvent(aEvent); +#ifdef MOZ_NUWA_PROCESS + { + ReentrantMonitorAutoEnter mon(mThreadStatusMonitor); + SetWorking(); +#endif // MOZ_NUWA_PROCESS + queue->PutEvent(aEvent); +#ifdef MOZ_NUWA_PROCESS + } +#endif // MOZ_NUWA_PROCESS // Make sure to grab the observer before dropping the lock, otherwise the // event that we just placed into the queue could run and eventually delete @@ -837,6 +857,15 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) --mRunningEvent; +#ifdef MOZ_NUWA_PROCESS + { + ReentrantMonitorAutoEnter mon(mThreadStatusMonitor); + if ((!mEvents->GetEvent(false, nullptr)) && (mRunningEvent == 0)) { + SetIdle(); + } + } +#endif // MOZ_NUWA_PROCESS + NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent, (this, mRunningEvent, *aResult)); @@ -1046,6 +1075,22 @@ nsThread::SetMainThreadObserver(nsIThreadObserver* aObserver) return NS_OK; } +#ifdef MOZ_NUWA_PROCESS +void +nsThread::SetWorking() +{ + nsThreadManager::get()->SetThreadIsWorking( + static_cast(mThreadStatusInfo), true); +} + +void +nsThread::SetIdle() +{ + nsThreadManager::get()->SetThreadIsWorking( + static_cast(mThreadStatusInfo), false); +} +#endif + //----------------------------------------------------------------------------- NS_IMETHODIMP diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index a9080972b89e..6ee9bac852c1 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -16,6 +16,7 @@ #include "nsTObserverArray.h" #include "mozilla/Attributes.h" #include "nsAutoPtr.h" +#include "mozilla/ReentrantMonitor.h" // A native thread class nsThread @@ -65,6 +66,14 @@ public: static nsresult SetMainThreadObserver(nsIThreadObserver* aObserver); +#ifdef MOZ_NUWA_PROCESS + void SetWorking(); + void SetIdle(); + mozilla::ReentrantMonitor& ThreadStatusMonitor() { + return mThreadStatusMonitor; + } +#endif + protected: static nsIThreadObserver* sMainThreadObserver; @@ -182,6 +191,12 @@ protected: // Set to true when events posted to this thread will never run. bool mEventsAreDoomed; MainThreadFlag mIsMainThread; +#ifdef MOZ_NUWA_PROCESS + mozilla::ReentrantMonitor mThreadStatusMonitor; + // The actual type is defined in nsThreadManager.h which is not exposed to + // file out of thread module. + void* mThreadStatusInfo; +#endif }; //----------------------------------------------------------------------------- diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 9ba0ee7d3f11..35f6e9d83cc7 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -11,6 +11,7 @@ #include "nsTArray.h" #include "nsAutoPtr.h" #include "mozilla/ThreadLocal.h" +#include "mozilla/ReentrantMonitor.h" #ifdef MOZ_CANARY #include #include @@ -47,6 +48,54 @@ NS_SetMainThread() typedef nsTArray> nsThreadArray; +#ifdef MOZ_NUWA_PROCESS +class NotifyAllThreadsWereIdle: public nsRunnable +{ +public: + + NotifyAllThreadsWereIdle( + nsTArray>* aListeners) + : mListeners(aListeners) + { + } + + virtual NS_IMETHODIMP + Run() { + // Copy listener array, which may be modified during call back. + nsTArray> arr(*mListeners); + for (size_t i = 0; i < arr.Length(); i++) { + arr[i]->OnAllThreadsWereIdle(); + } + return NS_OK; + } + +private: + // Raw pointer, since it's pointing to a member of thread manager. + nsTArray>* mListeners; +}; + +struct nsThreadManager::ThreadStatusInfo { + Atomic mWorking; + Atomic mWillBeWorking; + bool mIgnored; + nsThreadManager *mMgr; + ThreadStatusInfo(nsThreadManager *aManager) + : mWorking(false) + , mWillBeWorking(false) + , mIgnored(false) + , mMgr(aManager) + { + ReentrantMonitorAutoEnter mon(*(mMgr->mMonitor)); + mMgr->mThreadStatusInfos.AppendElement(this); + } + ~ThreadStatusInfo() + { + ReentrantMonitorAutoEnter mon(*(mMgr->mMonitor)); + mMgr->mThreadStatusInfos.RemoveElement(this); + } +}; +#endif // MOZ_NUWA_PROCESS + //----------------------------------------------------------------------------- static void @@ -55,6 +104,14 @@ ReleaseObject(void* aData) static_cast(aData)->Release(); } +#ifdef MOZ_NUWA_PROCESS +static void +DeleteThreadStatusInfo(void* aData) +{ + delete static_cast(aData); +} +#endif + static PLDHashOperator AppendAndRemoveThread(PRThread* aKey, nsRefPtr& aThread, void* aArg) { @@ -96,7 +153,17 @@ nsThreadManager::Init() return NS_ERROR_FAILURE; } +#ifdef MOZ_NUWA_PROCESS + if (PR_NewThreadPrivateIndex(&mThreadStatusInfoIndex, + DeleteThreadStatusInfo) == PR_FAILURE) { + return NS_ERROR_FAILURE; + } +#endif // MOZ_NUWA_PROCESS + mLock = new Mutex("nsThreadManager.mLock"); +#ifdef MOZ_NUWA_PROCESS + mMonitor = MakeUnique("nsThreadManager.mMonitor"); +#endif // MOZ_NUWA_PROCESS #ifdef MOZ_CANARY const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK; @@ -194,6 +261,9 @@ nsThreadManager::Shutdown() // Remove the TLS entry for the main thread. PR_SetThreadPrivate(mCurThreadIndex, nullptr); +#ifdef MOZ_NUWA_PROCESS + PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr); +#endif } void @@ -226,6 +296,9 @@ nsThreadManager::UnregisterCurrentThread(nsThread* aThread) PR_SetThreadPrivate(mCurThreadIndex, nullptr); // Ref-count balanced via ReleaseObject +#ifdef MOZ_NUWA_PROCESS + PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr); +#endif } nsThread* @@ -250,6 +323,21 @@ nsThreadManager::GetCurrentThread() return thread.get(); // reference held in TLS } +#ifdef MOZ_NUWA_PROCESS +nsThreadManager::ThreadStatusInfo* +nsThreadManager::GetCurrentThreadStatusInfo() +{ + void* data = PR_GetThreadPrivate(mThreadStatusInfoIndex); + if (!data) { + ThreadStatusInfo *thrInfo = new ThreadStatusInfo(this); + PR_SetThreadPrivate(mThreadStatusInfoIndex, thrInfo); + data = thrInfo; + } + + return static_cast(data); +} +#endif + NS_IMETHODIMP nsThreadManager::NewThread(uint32_t aCreationFlags, uint32_t aStackSize, @@ -342,3 +430,127 @@ nsThreadManager::GetHighestNumberOfThreads() MutexAutoLock lock(*mLock); return mHighestNumberOfThreads; } + +#ifdef MOZ_NUWA_PROCESS +void +nsThreadManager::SetIgnoreThreadStatus() +{ + GetCurrentThreadStatusInfo()->mIgnored = true; +} + +void +nsThreadManager::SetThreadIdle() +{ + SetThreadIsWorking(GetCurrentThreadStatusInfo(), false); +} + +void +nsThreadManager::SetThreadWorking() +{ + SetThreadIsWorking(GetCurrentThreadStatusInfo(), true); +} + +void +nsThreadManager::SetThreadIsWorking(ThreadStatusInfo* aInfo, bool aIsWorking) +{ + aInfo->mWillBeWorking = aIsWorking; + if (mThreadsIdledListeners.Length() > 0) { + + // A race condition occurs since we don't want threads to try to enter the + // monitor (nsThreadManager::mMonitor) when no one cares about their status. + // And thus the race can happen when we put the first listener into + // |mThreadsIdledListeners|: + // + // (1) Thread A wants to dispatch a task to Thread B. + // (2) Thread A checks |mThreadsIdledListeners|, and nothing is in the + // list. So Thread A decides not to enter |mMonitor| when updating B's + // status. + // (3) Thread A is suspended just before it changed status of B. + // (4) A listener is added to |mThreadsIdledListeners| + // (5) Now is Thread C's turn to run. Thread C finds there's something in + // |mThreadsIdledListeners|, so it enters |mMonitor| and check all + // thread info structs in |mThreadStatusInfos| while A is in the middle + // of changing B's status. + // + // Then C may find Thread B is an idle thread (which is not correct, because + // A attempted to change B's status prior to C starting to walk throught + // |mThreadStatusInfo|), but the fact that thread A is working (thread A + // hasn't finished dispatching a task to thread B) can prevent thread C from + // firing a bogus notification. + // + // If the state transition that happens outside the monitor is in the other + // direction, the race condition could be: + // + // (1) Thread D has just finished its jobs and wants to set its status to idle. + // (2) Thread D checks |mThreadsIdledListeners|, and nothing is in the list. + // So Thread D decides not to enter |mMonitor|. + // (3) Thread D is is suspended before it updates its own status. + // (4) A listener is put into |mThreadsIdledListeners|. + // (5) Thread C wants to changes status of itself. It checks + // |mThreadsIdledListeners| and finds something inside the list. Thread C + // then enters |mMonitor|, updates its status and checks thread info in + // |mThreadStatusInfos| while D is changing status of itself out of monitor. + // + // Thread C will find that thread D is working (D actually wants to change its + // status to idle before C starting to check), then C returns without firing + // any notification. Finding that thread D is working can make our checking + // mechanism miss a chance to fire a notification: because thread D thought + // there's nothing in |mThreadsIdledListeners| and thus won't check the + // |mThreadStatusInfos| after changing the status of itself. + // + // |mWillBeWorking| can be used to address this problem. We require each + // thread to put the value that is going to be set to |mWorking| to + // |mWillBeWorking| before the thread decide whether it should enter + // |mMonitor| to change status or not. Thus C finds that D is working while + // D's |mWillBeWorking| is false, and C realizes that D is just updating and + // can treat D as an idle thread. + // + // It doesn't matter whether D will check thread status after changing its + // own status or not. If D checks, which means D will enter the monitor + // before updating status, thus D must be blocked until C has finished + // dispatching the notification task to main thread, and D will find that main + // thread is working and will not fire an additional event. On the other hand, + // if D doesn't check |mThreadStatusInfos|, it's still ok, because C has + // treated D as an idle thread already. + + bool hasWorkingThread = false; + ReentrantMonitorAutoEnter mon(*mMonitor); + // Get data structure of thread info. + aInfo->mWorking = aIsWorking; + for (size_t i = 0; i < mThreadStatusInfos.Length(); i++) { + ThreadStatusInfo *info = mThreadStatusInfos[i]; + if (!info->mIgnored) { + if (info->mWorking) { + if (info->mWillBeWorking) { + hasWorkingThread = true; + break; + } + } + } + } + if (!hasWorkingThread) { + nsRefPtr runnable = + new NotifyAllThreadsWereIdle(&mThreadsIdledListeners); + NS_DispatchToMainThread(runnable); + } + } else { + // Update thread info without holding any lock. + aInfo->mWorking = aIsWorking; + } +} + + +void +nsThreadManager::AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener) +{ + MOZ_ASSERT(GetCurrentThreadStatusInfo()->mWorking); + mThreadsIdledListeners.AppendElement(listener); +} + +void +nsThreadManager::RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener) +{ + mThreadsIdledListeners.RemoveElement(listener); +} + +#endif // MOZ_NUWA_PROCESS diff --git a/xpcom/threads/nsThreadManager.h b/xpcom/threads/nsThreadManager.h index 54d9c5d561f6..70eceb471749 100644 --- a/xpcom/threads/nsThreadManager.h +++ b/xpcom/threads/nsThreadManager.h @@ -14,9 +14,26 @@ class nsIRunnable; +namespace mozilla { +class ReentrantMonitor; +} + class nsThreadManager : public nsIThreadManager { public: +#ifdef MOZ_NUWA_PROCESS + struct ThreadStatusInfo; + class AllThreadsWereIdleListener { + public: + NS_INLINE_DECL_REFCOUNTING(AllThreadsWereIdleListener); + virtual void OnAllThreadsWereIdle() = 0; + protected: + virtual ~AllThreadsWereIdleListener() + { + } + }; +#endif // MOZ_NUWA_PROCESS + NS_DECL_ISUPPORTS NS_DECL_NSITHREADMANAGER @@ -54,6 +71,17 @@ public: { } +#ifdef MOZ_NUWA_PROCESS + void SetIgnoreThreadStatus(); + void SetThreadIdle(); + void SetThreadWorking(); + void SetThreadIsWorking(ThreadStatusInfo* aInfo, bool aIsWorking); + + void AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener); + void RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener); + ThreadStatusInfo* GetCurrentThreadStatusInfo(); +#endif // MOZ_NUWA_PROCESS + private: nsThreadManager() : mCurThreadIndex(0) @@ -62,6 +90,9 @@ private: , mInitialized(false) , mCurrentNumberOfThreads(1) , mHighestNumberOfThreads(1) +#ifdef MOZ_NUWA_PROCESS + , mMonitor(nullptr) +#endif { } @@ -78,6 +109,13 @@ private: uint32_t mCurrentNumberOfThreads; // The highest number of threads encountered so far during the session uint32_t mHighestNumberOfThreads; + +#ifdef MOZ_NUWA_PROCESS + unsigned mThreadStatusInfoIndex; + nsTArray> mThreadsIdledListeners; + nsTArray mThreadStatusInfos; + mozilla::UniquePtr mMonitor; +#endif // MOZ_NUWA_PROCESS }; #define NS_THREADMANAGER_CID \ diff --git a/xpcom/threads/nsThreadPool.cpp b/xpcom/threads/nsThreadPool.cpp index 91c769438ef2..2cccc371158e 100644 --- a/xpcom/threads/nsThreadPool.cpp +++ b/xpcom/threads/nsThreadPool.cpp @@ -150,7 +150,6 @@ NS_IMETHODIMP nsThreadPool::Run() { LOG(("THRD-P(%p) enter\n", this)); - mThreadNaming.SetThreadPoolName(mName); nsCOMPtr current; @@ -208,6 +207,9 @@ nsThreadPool::Run() } else { PRIntervalTime delta = timeout - (now - idleSince); LOG(("THRD-P(%p) waiting [%d]\n", this, delta)); +#ifdef MOZ_NUWA_PROCESS + nsThreadManager::get()->SetThreadIdle(); +#endif // MOZ_NUWA_PROCESS mon.Wait(delta); } } else if (wasIdle) { @@ -217,6 +219,9 @@ nsThreadPool::Run() } if (event) { LOG(("THRD-P(%p) running [%p]\n", this, event.get())); +#ifdef MOZ_NUWA_PROCESS + nsThreadManager::get()->SetThreadWorking(); +#endif // MOZ_NUWA_PROCESS event->Run(); } } while (!exitThread); diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index 9803aacb0a86..7f1d6046a831 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -556,6 +556,13 @@ nsTimerImpl::Fire() return; } +#ifdef MOZ_NUWA_PROCESS + if (IsNuwaProcess() && IsNuwaReady()) { + // A timer event fired after Nuwa frozen can freeze main thread. + return; + } +#endif + PROFILER_LABEL("Timer", "Fire", js::ProfileEntry::Category::OTHER);