Backout change 39e167bbd14c, a80140872ea5, adae9be2294d and b71ccef9c674 (bug 970307).

This commit is contained in:
Cervantes Yu 2015-05-19 14:31:25 +08:00
parent a55e9225a2
commit 1d206cc826
24 changed files with 27 additions and 598 deletions

View File

@ -103,12 +103,6 @@ this.DOMApplicationRegistry = {
this.cpmm.addMessageListener(aMsgName, this);
}).bind(this));
this.resetList();
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
resetList: function() {
this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
messages: APPS_IPC_MSG_NAMES
});
@ -116,7 +110,6 @@ this.DOMApplicationRegistry = {
// We need to prime the cache with the list of apps.
let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
this.webapps = list.webapps;
// We need a fast mapping from localId -> app, so we add an index.
// We also add the manifest to the app object.
this.localIdIndex = { };
@ -125,6 +118,8 @@ this.DOMApplicationRegistry = {
this.localIdIndex[app.localId] = app;
app.manifest = list.manifests[id];
}
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(aSubject, aTopic, aData) {

View File

@ -538,12 +538,6 @@ NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
ContentChild* ContentChild::sSingleton;
static void
PostForkPreload()
{
TabChild::PostForkPreload();
}
// Performs initialization that is not fork-safe, i.e. that must be done after
// forking from the Nuwa process.
static void
@ -554,7 +548,6 @@ InitOnContentProcessCreated()
if (IsNuwaProcess()) {
return;
}
PostForkPreload();
nsCOMPtr<nsIPermissionManager> permManager =
services::GetPermissionManager();
@ -1356,6 +1349,7 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
{
// This runs after AllocPBrowserChild() returns and the IPC machinery for this
// PBrowserChild has been set up.
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
nsITabChild* tc =
@ -2201,11 +2195,8 @@ bool
ContentChild::RecvFlushMemory(const nsString& reason)
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess() || ManagedPBrowserChild().Length() == 0) {
if (IsNuwaProcess()) {
// Don't flush memory in the nuwa process: the GC thread could be frozen.
// If there's no PBrowser child, don't flush memory, either. GC writes
// to copy-on-write pages and makes preallocated process take more memory
// before it actually becomes an app.
return true;
}
#endif
@ -2299,28 +2290,12 @@ ContentChild::RecvAppInit()
// BrowserElementChild.js.
if ((mIsForApp || mIsForBrowser)
#ifdef MOZ_NUWA_PROCESS
&& IsNuwaProcess()
&& !IsNuwaProcess()
#endif
) {
PreloadSlowThings();
#ifndef MOZ_NUWA_PROCESS
PostForkPreload();
#endif
}
#ifdef MOZ_NUWA_PROCESS
// Some modules are initialized in preloading. We need to wait until the
// tasks they dispatched to chrome process are done.
if (IsNuwaProcess()) {
SendNuwaWaitForFreeze();
}
#endif
return true;
}
bool
ContentChild::RecvNuwaFreeze()
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
ContentChild::GetSingleton()->RecvGarbageCollect();
@ -2328,6 +2303,7 @@ ContentChild::RecvNuwaFreeze()
FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
}
#endif
return true;
}
@ -2604,36 +2580,6 @@ RunNuwaFork()
DoNuwaFork();
}
}
class NuwaForkCaller: public nsRunnable
{
public:
NS_IMETHODIMP
Run() {
// We want to ensure that the PBackground actor gets cloned in the Nuwa
// process before we freeze. Also, we have to do this to avoid deadlock.
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
// main thread to wait for the IPC thread during the open operation.
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
// the Nuwa process is forked. Unless we ensure that the two cannot happen
// at the same time then we risk deadlock. Spinning the event loop here
// guarantees the ordering is safe for PBackground.
if (!BackgroundChild::GetForCurrentThread()) {
// Dispatch ourself again.
NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
} else {
MessageLoop* ioloop = XRE_GetIOMessageLoop();
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
}
return NS_OK;
}
private:
virtual
~NuwaForkCaller()
{
}
};
#endif
bool
@ -2645,9 +2591,22 @@ ContentChild::RecvNuwaFork()
}
sNuwaForking = true;
nsRefPtr<NuwaForkCaller> runnable = new NuwaForkCaller();
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
// We want to ensure that the PBackground actor gets cloned in the Nuwa
// process before we freeze. Also, we have to do this to avoid deadlock.
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
// main thread to wait for the IPC thread during the open operation.
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
// the Nuwa process is forked. Unless we ensure that the two cannot happen
// at the same time then we risk deadlock. Spinning the event loop here
// guarantees the ordering is safe for PBackground.
while (!BackgroundChild::GetForCurrentThread()) {
if (NS_WARN_IF(!NS_ProcessNextEvent())) {
return false;
}
}
MessageLoop* ioloop = XRE_GetIOMessageLoop();
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
return true;
#else
return false; // Makes the underlying IPC channel abort.

View File

@ -379,8 +379,6 @@ public:
virtual bool RecvNotifyPhoneStateChange(const nsString& state) override;
virtual bool RecvNuwaFreeze() override;
void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
virtual bool RecvNotifyIdleObserver(const uint64_t& aObserver,

View File

@ -140,7 +140,6 @@
#include "nsServiceManagerUtils.h"
#include "nsStyleSheetService.h"
#include "nsThreadUtils.h"
#include "nsThreadManager.h"
#include "nsToolkitCompsCID.h"
#include "nsWidgetsCID.h"
#include "PreallocatedProcessManager.h"
@ -1563,28 +1562,6 @@ StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
nsITimerCallback)
#ifdef MOZ_NUWA_PROCESS
class NuwaFreezeListener : public nsThreadManager::AllThreadsWereIdleListener
{
public:
NuwaFreezeListener(ContentParent* parent)
: mParent(parent)
{
}
void OnAllThreadsWereIdle()
{
unused << mParent->SendNuwaFreeze();
nsThreadManager::get()->RemoveAllThreadsWereIdleListener(this);
}
private:
nsRefPtr<ContentParent> mParent;
virtual ~NuwaFreezeListener()
{
}
};
#endif // MOZ_NUWA_PROCESS
} // anonymous namespace
void
@ -2362,8 +2339,6 @@ ContentParent::ContentParent(ContentParent* aTemplate,
priority = PROCESS_PRIORITY_FOREGROUND;
}
mSendPermissionUpdates = aTemplate->mSendPermissionUpdates;
InitInternal(priority,
false, /* Setup Off-main thread compositing */
false /* Send registered chrome */);
@ -2527,7 +2502,7 @@ ContentParent::IsForApp()
#ifdef MOZ_NUWA_PROCESS
bool
ContentParent::IsNuwaProcess() const
ContentParent::IsNuwaProcess()
{
return mIsNuwaProcess;
}
@ -2902,19 +2877,6 @@ ContentParent::RecvNuwaReady()
#endif
}
bool
ContentParent::RecvNuwaWaitForFreeze()
{
#ifdef MOZ_NUWA_PROCESS
nsRefPtr<NuwaFreezeListener> listener = new NuwaFreezeListener(this);
nsThreadManager::get()->AddAllThreadsWereIdleListener(listener);
return true;
#else // MOZ_NUWA_PROCESS
NS_ERROR("ContentParent::RecvNuwaWaitForFreeze() not implemented!");
return false;
#endif // MOZ_NUWA_PROCESS
}
bool
ContentParent::RecvAddNewProcess(const uint32_t& aPid,
InfallibleTArray<ProtocolFdMapping>&& aFds)

View File

@ -233,7 +233,7 @@ public:
return mIsForBrowser;
}
#ifdef MOZ_NUWA_PROCESS
bool IsNuwaProcess() const;
bool IsNuwaProcess();
#endif
GeckoChildProcessHost* Process() {
@ -247,11 +247,7 @@ public:
}
bool NeedsPermissionsUpdate() const {
#ifdef MOZ_NUWA_PROCESS
return !IsNuwaProcess() && mSendPermissionUpdates;
#else
return mSendPermissionUpdates;
#endif
}
bool NeedsDataStoreInfos() const {
@ -783,8 +779,6 @@ private:
virtual bool RecvNuwaReady() override;
virtual bool RecvNuwaWaitForFreeze() override;
virtual bool RecvAddNewProcess(const uint32_t& aPid,
InfallibleTArray<ProtocolFdMapping>&& aFds) override;

View File

@ -632,7 +632,6 @@ child:
InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action);
EndDragSession(bool aDoneDrag, bool aUserCancelled);
NuwaFreeze();
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
@ -899,9 +898,6 @@ parent:
async SystemMessageHandled();
NuwaReady();
// Sent when nuwa finished its initialization process and is waiting for
// parent's signal to make it freeze.
NuwaWaitForFreeze();
sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);

View File

@ -775,21 +775,6 @@ TabChild::PreloadSlowThings()
ClearOnShutdown(&sPreallocatedTab);
}
/*static*/ void
TabChild::PostForkPreload()
{
// Preallocated Tab can be null if we are forked directly from b2g. In such
// case we don't need to preload anything, just return.
if (!sPreallocatedTab) {
return;
}
// Rebuild connections to parent.
sPreallocatedTab->RecvLoadRemoteScript(
NS_LITERAL_STRING("chrome://global/content/post-fork-preload.js"),
true);
}
/*static*/ already_AddRefed<TabChild>
TabChild::Create(nsIContentChild* aManager,
const TabId& aTabId,

View File

@ -263,7 +263,6 @@ public:
* on the critical path.
*/
static void PreloadSlowThings();
static void PostForkPreload();
/** Return a TabChild with the given attributes. */
static already_AddRefed<TabChild>

View File

@ -12,4 +12,3 @@ toolkit.jar:
content/global/manifestMessages.js (manifestMessages.js)
content/global/PushServiceChildPreload.js (../push/PushServiceChildPreload.js)
content/global/preload.js (preload.js)
content/global/post-fork-preload.js (post-fork-preload.js)

View File

@ -1,20 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Preload some things, in an attempt to make app startup faster.
//
// This script is run when the preallocated process starts. It is injected as
// a frame script.
// If Nuwa process is enabled, this script will run in preallocated process
// forked by Nuwa.
(function (global) {
"use strict";
Components.utils.import("resource://gre/modules/AppsServiceChild.jsm");
Components.classes["@mozilla.org/network/protocol-proxy-service;1"].
getService(Ci["nsIProtocolProxyService"]);
DOMApplicationRegistry.resetList();
})(this);

View File

@ -6,7 +6,6 @@
//
// This script is run when the preallocated process starts. It is injected as
// a frame script.
// If nuwa is enabled, this script will run in Nuwa process before frozen.
const BrowserElementIsPreloaded = true;
@ -59,6 +58,7 @@ const BrowserElementIsPreloaded = true;
Cc["@mozilla.org/network/idn-service;1"].getService(Ci["nsIIDNService"]);
Cc["@mozilla.org/network/io-service;1"].getService(Ci["nsIIOService2"]);
Cc["@mozilla.org/network/mime-hdrparam;1"].getService(Ci["nsIMIMEHeaderParam"]);
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci["nsISocketTransportService"]);
Cc["@mozilla.org/network/stream-transport-service;1"].getService(Ci["nsIStreamTransportService"]);
Cc["@mozilla.org/network/url-parser;1?auth=maybe"].getService(Ci["nsIURLParser"]);

View File

@ -67,9 +67,6 @@ public:
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
#ifdef MOZ_NUWA_PROCESS
NS_SetIgnoreStatusOfCurrentThread();
#endif
nsAutoString event;
gWpaSupplicant->WaitForEvent(event, mInterface);
if (!event.IsEmpty()) {

View File

@ -85,7 +85,6 @@
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
#include "prthread.h"
#include "nsThread.h"
#include "xpcpublic.h"
#ifdef ANDROID
@ -5107,17 +5106,6 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
{
MutexAutoLock lock(mMutex);
#ifdef MOZ_NUWA_PROCESS
{
nsThread *thr = static_cast<nsThread*>(NS_GetCurrentThread());
ReentrantMonitorAutoEnter mon(thr->ThreadStatusMonitor());
if (mControlQueue.IsEmpty() &&
!(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
thr->SetIdle();
}
}
#endif // MOZ_NUWA_PROCESS
while (mControlQueue.IsEmpty() &&
!(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
!(normalRunnablesPending = NS_HasPendingEvents(mThread))) {

View File

@ -753,7 +753,6 @@ nsSocketTransportService::Run()
if (IsNuwaProcess()) {
NuwaMarkCurrentThread(nullptr, nullptr);
}
NS_SetIgnoreStatusOfCurrentThread();
#endif
SOCKET_LOG(("STS thread init\n"));

View File

@ -127,8 +127,6 @@ public:
}
#endif
NS_SetIgnoreStatusOfCurrentThread();
int lowMemFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active",
O_RDONLY | O_CLOEXEC);
NS_ENSURE_STATE(lowMemFd != -1);

View File

@ -375,11 +375,3 @@ 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

View File

@ -1019,19 +1019,4 @@ 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__

View File

@ -205,7 +205,6 @@ TimerThread::Run()
}
#endif
NS_SetIgnoreStatusOfCurrentThread();
MonitorAutoLock lock(mMonitor);
// We need to know how many microseconds give a positive PRIntervalTime. This

View File

@ -15,6 +15,7 @@
#undef LOG
#endif
#include "mozilla/ReentrantMonitor.h"
#include "nsMemoryPressure.h"
#include "nsThreadManager.h"
#include "nsIClassInfoImpl.h"
@ -330,10 +331,6 @@ nsThread::ThreadFunc(void* aArg)
// Inform the ThreadManager
nsThreadManager::get()->RegisterCurrentThread(self);
#ifdef MOZ_NUWA_PROCESS
self->mThreadStatusInfo =
static_cast<void*>(nsThreadManager::get()->GetCurrentThreadStatusInfo());
#endif
#if !defined(MOZILLA_XPCOMRT_API)
mozilla::IOInterposer::RegisterCurrentThread();
@ -451,10 +448,6 @@ nsThread::nsThread(MainThreadFlag aMainThread, uint32_t aStackSize)
, mShutdownRequired(false)
, mEventsAreDoomed(false)
, mIsMainThread(aMainThread)
#ifdef MOZ_NUWA_PROCESS
, mThreadStatusMonitor("nsThread.mThreadStatusLock")
, mThreadStatusInfo(nullptr)
#endif
{
}
@ -502,11 +495,6 @@ nsThread::InitCurrentThread()
SetupCurrentThreadForChaosMode();
nsThreadManager::get()->RegisterCurrentThread(this);
#ifdef MOZ_NUWA_PROCESS
mThreadStatusInfo =
static_cast<void*>(nsThreadManager::get()->GetCurrentThreadStatusInfo());
#endif
return NS_OK;
}
@ -522,15 +510,7 @@ 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;
}
#ifdef MOZ_NUWA_PROCESS
{
ReentrantMonitorAutoEnter mon(mThreadStatusMonitor);
SetWorking();
#endif // MOZ_NUWA_PROCESS
queue->PutEvent(aEvent);
#ifdef MOZ_NUWA_PROCESS
}
#endif // MOZ_NUWA_PROCESS
queue->PutEvent(aEvent);
// 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
@ -873,27 +853,6 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
--mNestedEventLoopDepth;
#ifdef MOZ_NUWA_PROCESS
nsCOMPtr<nsIRunnable> notifyAllIdleRunnable;
{
ReentrantMonitorAutoEnter mon(mThreadStatusMonitor);
if ((!mEvents->GetEvent(false, nullptr)) && (mNestedEventLoopDepth == 0)) {
nsThreadManager::get()->SetThreadIsWorking(
static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
false, getter_AddRefs(notifyAllIdleRunnable));
}
}
if (notifyAllIdleRunnable) {
// Dispatching a task leads us to acquire |mLock| of the thread. If we
// dispatch to main thread while holding main thread's
// |mThreadStatusMonitor|, deadlock could happen if other thread is
// blocked by main thread's |mThreadStatusMonitor| and is holding
// main thread's |mLock|.
Dispatch(notifyAllIdleRunnable, NS_DISPATCH_NORMAL);
nsThreadManager::get()->ResetIsDispatchingToMainThread();
}
#endif // MOZ_NUWA_PROCESS
NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent,
(this, mNestedEventLoopDepth, *aResult));
@ -1104,24 +1063,6 @@ nsThread::SetMainThreadObserver(nsIThreadObserver* aObserver)
return NS_OK;
}
#ifdef MOZ_NUWA_PROCESS
void
nsThread::SetWorking()
{
nsThreadManager::get()->SetThreadIsWorking(
static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
true, nullptr);
}
void
nsThread::SetIdle()
{
nsThreadManager::get()->SetThreadIsWorking(
static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
false, nullptr);
}
#endif
//-----------------------------------------------------------------------------
NS_IMETHODIMP

View File

@ -16,7 +16,6 @@
#include "nsTObserverArray.h"
#include "mozilla/Attributes.h"
#include "nsAutoPtr.h"
#include "mozilla/ReentrantMonitor.h"
// A native thread
class nsThread
@ -66,14 +65,6 @@ public:
static nsresult
SetMainThreadObserver(nsIThreadObserver* aObserver);
#ifdef MOZ_NUWA_PROCESS
void SetWorking();
void SetIdle();
mozilla::ReentrantMonitor& ThreadStatusMonitor() {
return mThreadStatusMonitor;
}
#endif
protected:
static nsIThreadObserver* sMainThreadObserver;
@ -191,12 +182,6 @@ 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
};
//-----------------------------------------------------------------------------

View File

@ -11,7 +11,6 @@
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/ReentrantMonitor.h"
#ifdef MOZ_CANARY
#include <fcntl.h>
#include <unistd.h>
@ -41,45 +40,6 @@ NS_SetMainThread()
typedef nsTArray<nsRefPtr<nsThread>> nsThreadArray;
#ifdef MOZ_NUWA_PROCESS
class NotifyAllThreadsWereIdle: public nsRunnable
{
public:
NotifyAllThreadsWereIdle(
nsTArray<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>>* aListeners)
: mListeners(aListeners)
{
}
virtual NS_IMETHODIMP
Run() {
// Copy listener array, which may be modified during call back.
nsTArray<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>> 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<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>>* mListeners;
};
struct nsThreadManager::ThreadStatusInfo {
Atomic<bool> mWorking;
Atomic<bool> mWillBeWorking;
bool mIgnored;
ThreadStatusInfo()
: mWorking(false)
, mWillBeWorking(false)
, mIgnored(false)
{
}
};
#endif // MOZ_NUWA_PROCESS
//-----------------------------------------------------------------------------
static void
@ -88,24 +48,6 @@ ReleaseObject(void* aData)
static_cast<nsISupports*>(aData)->Release();
}
#ifdef MOZ_NUWA_PROCESS
void
nsThreadManager::DeleteThreadStatusInfo(void* aData)
{
nsThreadManager* mgr = nsThreadManager::get();
nsThreadManager::ThreadStatusInfo* thrInfo =
static_cast<nsThreadManager::ThreadStatusInfo*>(aData);
{
ReentrantMonitorAutoEnter mon(*(mgr->mMonitor));
mgr->mThreadStatusInfos.RemoveElement(thrInfo);
if (NS_IsMainThread()) {
mgr->mMainThreadStatusInfo = nullptr;
}
}
delete thrInfo;
}
#endif
static PLDHashOperator
AppendAndRemoveThread(PRThread* aKey, nsRefPtr<nsThread>& aThread, void* aArg)
{
@ -147,17 +89,6 @@ nsThreadManager::Init()
return NS_ERROR_FAILURE;
}
#ifdef MOZ_NUWA_PROCESS
if (PR_NewThreadPrivateIndex(
&mThreadStatusInfoIndex,
nsThreadManager::DeleteThreadStatusInfo) == PR_FAILURE) {
return NS_ERROR_FAILURE;
}
#endif // MOZ_NUWA_PROCESS
#ifdef MOZ_NUWA_PROCESS
mMonitor = MakeUnique<ReentrantMonitor>("nsThreadManager.mMonitor");
#endif // MOZ_NUWA_PROCESS
#ifdef MOZ_CANARY
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
@ -250,9 +181,6 @@ nsThreadManager::Shutdown()
// Remove the TLS entry for the main thread.
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
#ifdef MOZ_NUWA_PROCESS
PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr);
#endif
}
void
@ -285,9 +213,6 @@ nsThreadManager::UnregisterCurrentThread(nsThread* aThread)
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
// Ref-count balanced via ReleaseObject
#ifdef MOZ_NUWA_PROCESS
PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr);
#endif
}
nsThread*
@ -312,27 +237,6 @@ 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();
PR_SetThreadPrivate(mThreadStatusInfoIndex, thrInfo);
data = thrInfo;
ReentrantMonitorAutoEnter mon(*mMonitor);
mThreadStatusInfos.AppendElement(thrInfo);
if (NS_IsMainThread()) {
mMainThreadStatusInfo = thrInfo;
}
}
return static_cast<ThreadStatusInfo*>(data);
}
#endif
NS_IMETHODIMP
nsThreadManager::NewThread(uint32_t aCreationFlags,
uint32_t aStackSize,
@ -429,157 +333,3 @@ nsThreadManager::GetHighestNumberOfThreads()
OffTheBooksMutexAutoLock lock(mLock);
return mHighestNumberOfThreads;
}
#ifdef MOZ_NUWA_PROCESS
void
nsThreadManager::SetIgnoreThreadStatus()
{
GetCurrentThreadStatusInfo()->mIgnored = true;
}
void
nsThreadManager::SetThreadIdle(nsIRunnable **aReturnRunnable)
{
SetThreadIsWorking(GetCurrentThreadStatusInfo(), false, aReturnRunnable);
}
void
nsThreadManager::SetThreadWorking()
{
SetThreadIsWorking(GetCurrentThreadStatusInfo(), true, nullptr);
}
void
nsThreadManager::SetThreadIsWorking(ThreadStatusInfo* aInfo,
bool aIsWorking,
nsIRunnable **aReturnRunnable)
{
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;
nsRefPtr<NotifyAllThreadsWereIdle> runnable;
{
ReentrantMonitorAutoEnter mon(*mMonitor);
// Get data structure of thread info.
aInfo->mWorking = aIsWorking;
if (aIsWorking) {
// We are working, so there's no need to check futher.
return;
}
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 && !mDispatchingToMainThread) {
runnable = new NotifyAllThreadsWereIdle(&mThreadsIdledListeners);
mDispatchingToMainThread = true;
}
}
if (runnable) {
if (NS_IsMainThread()) {
// We are holding the main thread's |nsThread::mThreadStatusMonitor|.
// If we dispatch a task to ourself, then we are in danger of causing
// deadlock. Instead, return the task, and let the caller dispatch it
// for us.
MOZ_ASSERT(aReturnRunnable,
"aReturnRunnable must be provided on main thread");
runnable.forget(aReturnRunnable);
} else {
NS_DispatchToMainThread(runnable);
ResetIsDispatchingToMainThread();
}
}
} else {
// Update thread info without holding any lock.
aInfo->mWorking = aIsWorking;
}
}
void
nsThreadManager::ResetIsDispatchingToMainThread()
{
ReentrantMonitorAutoEnter mon(*mMonitor);
mDispatchingToMainThread = false;
}
void
nsThreadManager::AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener)
{
MOZ_ASSERT(GetCurrentThreadStatusInfo()->mWorking);
mThreadsIdledListeners.AppendElement(listener);
}
void
nsThreadManager::RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener)
{
mThreadsIdledListeners.RemoveElement(listener);
}
#endif // MOZ_NUWA_PROCESS

View File

@ -14,26 +14,9 @@
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
@ -71,31 +54,6 @@ public:
{
}
#ifdef MOZ_NUWA_PROCESS
void SetIgnoreThreadStatus();
// |SetThreadWorking| and |SetThreadIdle| set status of thread that is
// currently running. They get thread status information from TLS and pass
// the information to |SetThreadIsWorking|.
void SetThreadIdle(nsIRunnable** aReturnRunnable);
void SetThreadWorking();
// |SetThreadIsWorking| is where is status actually changed. Thread status
// information is passed as a argument so caller must obtain the structure
// by itself. If this method is invoked on main thread, |aReturnRunnable|
// should be provided to receive the runnable of notifying listeners.
// |ResetIsDispatchingToMainThread| should be invoked after caller on main
// thread dispatched the task to main thread's queue.
void SetThreadIsWorking(ThreadStatusInfo* aInfo,
bool aIsWorking,
nsIRunnable** aReturnRunnable);
void ResetIsDispatchingToMainThread();
void AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
void RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
ThreadStatusInfo* GetCurrentThreadStatusInfo();
#endif // MOZ_NUWA_PROCESS
private:
nsThreadManager()
: mCurThreadIndex(0)
@ -104,11 +62,6 @@ private:
, mInitialized(false)
, mCurrentNumberOfThreads(1)
, mHighestNumberOfThreads(1)
#ifdef MOZ_NUWA_PROCESS
, mMonitor(nullptr)
, mMainThreadStatusInfo(nullptr)
, mDispatchingToMainThread(nullptr)
#endif
{
}
@ -123,19 +76,6 @@ private:
uint32_t mCurrentNumberOfThreads;
// The highest number of threads encountered so far during the session
uint32_t mHighestNumberOfThreads;
#ifdef MOZ_NUWA_PROCESS
static void DeleteThreadStatusInfo(void *aData);
unsigned mThreadStatusInfoIndex;
nsTArray<nsRefPtr<AllThreadsWereIdleListener>> mThreadsIdledListeners;
nsTArray<ThreadStatusInfo*> mThreadStatusInfos;
mozilla::UniquePtr<mozilla::ReentrantMonitor> mMonitor;
ThreadStatusInfo* mMainThreadStatusInfo;
// |mDispatchingToMainThread| is set when all thread are found to be idle
// before task of notifying all listeners are dispatched to main thread.
// The flag is protected by |mMonitor|.
bool mDispatchingToMainThread;
#endif // MOZ_NUWA_PROCESS
};
#define NS_THREADMANAGER_CID \

View File

@ -151,6 +151,7 @@ NS_IMETHODIMP
nsThreadPool::Run()
{
LOG(("THRD-P(%p) enter\n", this));
mThreadNaming.SetThreadPoolName(mName);
nsCOMPtr<nsIThread> current;
@ -208,9 +209,6 @@ nsThreadPool::Run()
} else {
PRIntervalTime delta = timeout - (now - idleSince);
LOG(("THRD-P(%p) waiting [%d]\n", this, delta));
#ifdef MOZ_NUWA_PROCESS
nsThreadManager::get()->SetThreadIdle(nullptr);
#endif // MOZ_NUWA_PROCESS
mon.Wait(delta);
}
} else if (wasIdle) {
@ -220,9 +218,6 @@ 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);

View File

@ -549,13 +549,6 @@ nsTimerImpl::Fire()
return;
}
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess() && IsNuwaReady()) {
// A timer event fired after Nuwa frozen can freeze main thread.
return;
}
#endif
#if !defined(MOZILLA_XPCOMRT_API)
PROFILER_LABEL("Timer", "Fire",
js::ProfileEntry::Category::OTHER);