Bug 1324428 - Simplified preallocated process manager. r=billm

This commit is contained in:
Gabor Krizsanits 2017-02-01 13:34:24 +01:00
Родитель ac517a4bf4
Коммит 882d1434a2
11 изменённых файлов: 609 добавлений и 42 удалений

Просмотреть файл

@ -1398,6 +1398,15 @@ ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL,
return IPC_OK();
}
static StaticRefPtr<CancelableRunnable> gFirstIdleTask;
static void
FirstIdle(void)
{
MOZ_ASSERT(gFirstIdleTask);
gFirstIdleTask = nullptr;
ContentChild::GetSingleton()->SendFirstIdle();
}
mozilla::jsipc::PJavaScriptChild *
ContentChild::AllocPJavaScriptChild()
@ -1457,6 +1466,15 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
{
MOZ_ASSERT(!IsShuttingDown());
static bool hasRunOnce = false;
if (!hasRunOnce) {
hasRunOnce = true;
MOZ_ASSERT(!gFirstIdleTask);
RefPtr<CancelableRunnable> firstIdleTask = NewCancelableRunnableFunction(FirstIdle);
gFirstIdleTask = firstIdleTask;
NS_IdleDispatchToCurrentThread(firstIdleTask.forget());
}
return nsIContentChild::RecvPBrowserConstructor(aActor, aTabId, aContext,
aChromeFlags, aCpID, aIsForBrowser);
}
@ -1995,6 +2013,9 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
// keep persistent state.
ProcessChild::QuickExit();
#else
if (gFirstIdleTask) {
gFirstIdleTask->Cancel();
}
nsHostObjectProtocolHandler::RemoveDataEntries();

Просмотреть файл

@ -156,6 +156,7 @@
#include "nsThreadUtils.h"
#include "nsToolkitCompsCID.h"
#include "nsWidgetsCID.h"
#include "PreallocatedProcessManager.h"
#include "ProcessPriorityManager.h"
#include "SandboxHal.h"
#include "ScreenManagerParent.h"
@ -476,6 +477,23 @@ static const char* sObserverTopics[] = {
"cacheservice:empty-cache",
};
// PreallocateProcess is called by the PreallocatedProcessManager.
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
/*static*/ already_AddRefed<ContentParent>
ContentParent::PreallocateProcess()
{
RefPtr<ContentParent> process =
new ContentParent(/* aOpener = */ nullptr,
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
if (!process->LaunchSubprocess(PROCESS_PRIORITY_PREALLOC)) {
return nullptr;
}
process->Init();
return process.forget();
}
/*static*/ void
ContentParent::StartUp()
{
@ -509,6 +527,9 @@ ContentParent::StartUp()
BackgroundChild::Startup();
// Try to preallocate a process that we can use later.
PreallocatedProcessManager::AllocateAfterDelay();
sDisableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
@ -575,6 +596,74 @@ ContentParent::JoinAllSubprocesses()
sCanLaunchSubprocesses = false;
}
/*static*/ uint32_t
ContentParent::GetPoolSize(const nsAString& aContentProcessType)
{
if (!sBrowserContentParents) {
return 0;
}
nsTArray<ContentParent*>* parents =
sBrowserContentParents->Get(aContentProcessType);
return parents ? parents->Length() : 0;
}
/*static*/ nsTArray<ContentParent*>&
ContentParent::GetOrCreatePool(const nsAString& aContentProcessType)
{
if (!sBrowserContentParents) {
sBrowserContentParents =
new nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>;
}
return *sBrowserContentParents->LookupOrAdd(aContentProcessType);
}
/*static*/ uint32_t
ContentParent::GetMaxProcessCount(const nsAString& aContentProcessType)
{
int32_t maxContentParents;
nsAutoCString processCountPref("dom.ipc.processCount.");
processCountPref.Append(NS_ConvertUTF16toUTF8(aContentProcessType));
if (NS_FAILED(Preferences::GetInt(processCountPref.get(), &maxContentParents))) {
maxContentParents = Preferences::GetInt("dom.ipc.processCount", 1);
}
if (maxContentParents < 1) {
maxContentParents = 1;
}
return static_cast<uint32_t>(maxContentParents);
}
/*static*/ bool
ContentParent::IsMaxProcessCountReached(const nsAString& aContentProcessType)
{
return GetPoolSize(aContentProcessType) >= GetMaxProcessCount(aContentProcessType);
}
/*static*/ already_AddRefed<ContentParent>
ContentParent::RandomSelect(const nsTArray<ContentParent*>& aContentParents,
ContentParent* aOpener, int32_t aMaxContentParents)
{
uint32_t maxSelectable = std::min(static_cast<uint32_t>(aContentParents.Length()),
static_cast<uint32_t>(aMaxContentParents));
uint32_t startIdx = rand() % maxSelectable;
uint32_t currIdx = startIdx;
do {
RefPtr<ContentParent> p = aContentParents[currIdx];
NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sBrowserContentParents?");
if (p->mOpener == aOpener) {
return p.forget();
}
currIdx = (currIdx + 1) % maxSelectable;
} while (currIdx != startIdx);
return nullptr;
}
/*static*/ already_AddRefed<ContentParent>
ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
ProcessPriority aPriority,
@ -585,58 +674,42 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
if (aNew) {
*aNew = false;
}
if (!sBrowserContentParents) {
sBrowserContentParents =
new nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>;
}
// Decide which pool of content parents we are going to be pulling from based
// on the aRemoteType and aLargeAllocationProcess flag.
nsAutoString contentProcessType(aLargeAllocationProcess
? NS_LITERAL_STRING(LARGE_ALLOCATION_REMOTE_TYPE)
: aRemoteType);
nsTArray<ContentParent*>* contentParents =
sBrowserContentParents->LookupOrAdd(contentProcessType);
int32_t maxContentParents;
nsAutoCString processCountPref("dom.ipc.processCount.");
processCountPref.Append(NS_ConvertUTF16toUTF8(contentProcessType));
if (NS_FAILED(Preferences::GetInt(processCountPref.get(), &maxContentParents))) {
maxContentParents = Preferences::GetInt("dom.ipc.processCount", 1);
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(contentProcessType);
uint32_t maxContentParents = GetMaxProcessCount(contentProcessType);
RefPtr<ContentParent> p;
if (contentParents.Length() >= uint32_t(maxContentParents) &&
(p = RandomSelect(contentParents, aOpener, maxContentParents))) {
return p.forget();
}
if (maxContentParents < 1) {
maxContentParents = 1;
// Try to take the preallocated process only for the default process type.
if (contentProcessType.Equals(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)) &&
(p = PreallocatedProcessManager::Take())) {
// For pre-allocated process we have not set the opener yet.
p->mOpener = aOpener;
} else {
p = new ContentParent(aOpener, contentProcessType);
if (aNew) {
*aNew = true;
}
if (!p->LaunchSubprocess(aPriority)) {
return nullptr;
}
p->Init();
}
if (contentParents->Length() >= uint32_t(maxContentParents)) {
uint32_t maxSelectable = std::min(static_cast<uint32_t>(contentParents->Length()),
static_cast<uint32_t>(maxContentParents));
uint32_t startIdx = rand() % maxSelectable;
uint32_t currIdx = startIdx;
do {
RefPtr<ContentParent> p = (*contentParents)[currIdx];
NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sBrowserContentParents?");
if (p->mOpener == aOpener) {
return p.forget();
}
currIdx = (currIdx + 1) % maxSelectable;
} while (currIdx != startIdx);
}
RefPtr<ContentParent> p = new ContentParent(aOpener, contentProcessType);
if (aNew) {
*aNew = true;
}
if (!p->LaunchSubprocess(aPriority)) {
return nullptr;
}
p->Init();
contentParents->AppendElement(p);
contentParents.AppendElement(p);
return p.forget();
}
@ -2250,6 +2323,17 @@ ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvFirstIdle()
{
// When the ContentChild goes idle, it sends us a FirstIdle message
// which we use as a good time to prelaunch another process. If we
// prelaunch any sooner than this, then we'll be competing with the
// child process and slowing it down.
PreallocatedProcessManager::AllocateAfterDelay();
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden)
@ -2552,6 +2636,13 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
SerializeURI(nullptr, *aUserContentCSSURL);
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get());
}
return IPC_OK();
}

Просмотреть файл

@ -63,6 +63,8 @@ class SandboxBroker;
class SandboxBrokerPolicyFactory;
#endif
class PreallocatedProcessManagerImpl;
namespace embedding {
class PrintingParent;
}
@ -116,10 +118,17 @@ class ContentParent final : public PContentParent
typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
friend class mozilla::PreallocatedProcessManagerImpl;
public:
virtual bool IsContentParent() const override { return true; }
/**
* Create a subprocess suitable for use later as a content process.
*/
static already_AddRefed<ContentParent> PreallocateProcess();
/**
* Start up the content-process machinery. This might include
* scheduling pre-launch tasks.
@ -137,6 +146,22 @@ public:
*/
static void JoinAllSubprocesses();
static uint32_t GetPoolSize(const nsAString& aContentProcessType);
static uint32_t GetMaxProcessCount(const nsAString& aContentProcessType);
static bool IsMaxProcessCountReached(const nsAString& aContentProcessType);
/**
* Picks a random content parent from |aContentParents| with a given |aOpener|
* respecting the index limit set by |aMaxContentParents|.
* Returns null if non available.
*/
static already_AddRefed<ContentParent>
RandomSelect(const nsTArray<ContentParent*>& aContentParents,
ContentParent* aOpener,
int32_t maxContentParents);
/**
* Get or create a content process for:
* 1. browser iframe
@ -713,6 +738,11 @@ private:
TabParent* aTopLevel, const TabId& aTabId,
uint64_t* aId);
/**
* Get or create the corresponding content parent array to |aContentProcessType|.
*/
static nsTArray<ContentParent*>& GetOrCreatePool(const nsAString& aContentProcessType);
virtual mozilla::ipc::IPCResult RecvInitBackground(Endpoint<mozilla::ipc::PBackgroundParent>&& aEndpoint) override;
virtual mozilla::ipc::IPCResult RecvGetProcessAttributes(ContentParentId* aCpId,
@ -965,6 +995,8 @@ private:
virtual mozilla::ipc::IPCResult RecvPrivateDocShellsExist(const bool& aExist) override;
virtual mozilla::ipc::IPCResult RecvFirstIdle() override;
virtual mozilla::ipc::IPCResult RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden) override;

Просмотреть файл

@ -896,6 +896,9 @@ parent:
// Notify the parent of the presence or absence of private docshells
async PrivateDocShellsExist(bool aExist);
// Tell the parent that the child has gone idle for the first time.
async FirstIdle();
async AudioChannelServiceStatus(bool aActiveTelephonyChannel,
bool aContentOrNormalChannel,
bool aAnyActiveChannel);

Просмотреть файл

@ -0,0 +1,278 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/PreallocatedProcessManager.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIPropertyBag2.h"
#include "ProcessPriorityManager.h"
#include "nsServiceManagerUtils.h"
// This number is fairly arbitrary ... the intention is to put off
// launching another app process until the last one has finished
// loading its content, to reduce CPU/memory/IO contention.
#define DEFAULT_ALLOCATE_DELAY 1000
using namespace mozilla;
using namespace mozilla::hal;
using namespace mozilla::dom;
namespace mozilla {
/**
* This singleton class implements the static methods on
* PreallocatedProcessManager.
*/
class PreallocatedProcessManagerImpl final
: public nsIObserver
{
public:
static PreallocatedProcessManagerImpl* Singleton();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
// See comments on PreallocatedProcessManager for these methods.
void AllocateAfterDelay();
void AllocateOnIdle();
void AllocateNow();
already_AddRefed<ContentParent> Take();
private:
static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
PreallocatedProcessManagerImpl();
~PreallocatedProcessManagerImpl() {}
DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManagerImpl);
void Init();
void RereadPrefs();
void Enable();
void Disable();
void CloseProcess();
void ObserveProcessShutdown(nsISupports* aSubject);
bool mEnabled;
bool mShutdown;
RefPtr<ContentParent> mPreallocatedProcess;
};
/* static */ StaticRefPtr<PreallocatedProcessManagerImpl>
PreallocatedProcessManagerImpl::sSingleton;
/* static */ PreallocatedProcessManagerImpl*
PreallocatedProcessManagerImpl::Singleton()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sSingleton) {
sSingleton = new PreallocatedProcessManagerImpl();
sSingleton->Init();
ClearOnShutdown(&sSingleton);
}
// First time when we init sSingleton, the pref database might not be in a
// reliable state (we are too early), so despite dom.ipc.processPrelaunch.enabled
// is set to true Preferences::GetBool will return false (it cannot find the pref).
// Since Init() above will be called only once, and the pref will not be changed,
// the manger will stay disabled. To prevent that let's re-read the pref each time
// someone accessing the manager singleton. This is a hack but this is not a hot code
// so it should be fine.
sSingleton->RereadPrefs();
return sSingleton;
}
NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)
PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
: mEnabled(false)
, mShutdown(false)
{}
void
PreallocatedProcessManagerImpl::Init()
{
Preferences::AddStrongObserver(this, "dom.ipc.processPrelaunch.enabled");
// We have to respect processCount at all time. This is especially important
// for testing.
Preferences::AddStrongObserver(this, "dom.ipc.processCount");
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->AddObserver(this, "ipc:content-shutdown",
/* weakRef = */ false);
os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
/* weakRef = */ false);
}
RereadPrefs();
}
NS_IMETHODIMP
PreallocatedProcessManagerImpl::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!strcmp("ipc:content-shutdown", aTopic)) {
ObserveProcessShutdown(aSubject);
} else if (!strcmp("nsPref:changed", aTopic)) {
// The only other observer we registered was for our prefs.
RereadPrefs();
} else if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
Preferences::RemoveObserver(this, "dom.ipc.processPrelaunch.enabled");
Preferences::RemoveObserver(this, "dom.ipc.processCount");
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->RemoveObserver(this, "ipc:content-shutdown");
os->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
} else {
MOZ_ASSERT(false);
}
return NS_OK;
}
void
PreallocatedProcessManagerImpl::RereadPrefs()
{
if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled")) {
Enable();
} else {
Disable();
}
if (ContentParent::IsMaxProcessCountReached(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE))) {
CloseProcess();
}
}
already_AddRefed<ContentParent>
PreallocatedProcessManagerImpl::Take()
{
return mPreallocatedProcess.forget();
}
void
PreallocatedProcessManagerImpl::Enable()
{
if (mEnabled) {
return;
}
mEnabled = true;
AllocateAfterDelay();
}
void
PreallocatedProcessManagerImpl::AllocateAfterDelay()
{
if (!mEnabled || mPreallocatedProcess) {
return;
}
// Originally AllocateOnIdle() was post here, but since the gecko parent
// message loop in practice never goes idle, that didn't work out well.
// Let's just launch the process after the delay.
NS_DelayedDispatchToCurrentThread(
NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow),
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
DEFAULT_ALLOCATE_DELAY));
}
void
PreallocatedProcessManagerImpl::AllocateOnIdle()
{
if (!mEnabled || mPreallocatedProcess) {
return;
}
NS_IdleDispatchToCurrentThread(NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow));
}
void
PreallocatedProcessManagerImpl::AllocateNow()
{
if (!mEnabled || mPreallocatedProcess ||
ContentParent::IsMaxProcessCountReached(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE))) {
return;
}
mPreallocatedProcess = ContentParent::PreallocateProcess();
}
void
PreallocatedProcessManagerImpl::Disable()
{
if (!mEnabled) {
return;
}
mEnabled = false;
CloseProcess();
}
void
PreallocatedProcessManagerImpl::CloseProcess()
{
if (mPreallocatedProcess) {
mPreallocatedProcess->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE);
mPreallocatedProcess = nullptr;
}
}
void
PreallocatedProcessManagerImpl::ObserveProcessShutdown(nsISupports* aSubject)
{
if (!mPreallocatedProcess) {
return;
}
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
NS_ENSURE_TRUE_VOID(props);
uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
if (childID == mPreallocatedProcess->ChildID()) {
mPreallocatedProcess = nullptr;
}
}
inline PreallocatedProcessManagerImpl* GetPPMImpl()
{
return PreallocatedProcessManagerImpl::Singleton();
}
/* static */ void
PreallocatedProcessManager::AllocateAfterDelay()
{
GetPPMImpl()->AllocateAfterDelay();
}
/* static */ void
PreallocatedProcessManager::AllocateOnIdle()
{
GetPPMImpl()->AllocateOnIdle();
}
/* static */ void
PreallocatedProcessManager::AllocateNow()
{
GetPPMImpl()->AllocateNow();
}
/* static */ already_AddRefed<ContentParent>
PreallocatedProcessManager::Take()
{
return GetPPMImpl()->Take();
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_PreallocatedProcessManager_h
#define mozilla_PreallocatedProcessManager_h
#include "base/basictypes.h"
#include "mozilla/AlreadyAddRefed.h"
namespace mozilla {
namespace dom {
class ContentParent;
} // namespace dom
/**
* This class manages a ContentParent that it starts up ahead of any particular
* need. You can then call Take() to get this process and use it. Since we
* already started it up, it should be ready for use faster than if you'd
* created the process when you needed it.
*
* This class watches the dom.ipc.processPrelaunch.enabled pref. If it changes
* from false to true, it preallocates a process. If it changes from true to
* false, it kills the preallocated process, if any.
*
* We don't expect this pref to flip between true and false in production, but
* flipping the pref is important for tests.
*/
class PreallocatedProcessManager final
{
typedef mozilla::dom::ContentParent ContentParent;
public:
/**
* Create a process after a delay. We wait for a period of time (specified
* by the dom.ipc.processPrelaunch.delayMs pref), then wait for this process
* to go idle, then allocate the new process.
*
* If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
* have a preallocated process, this function does nothing.
*/
static void AllocateAfterDelay();
/**
* Create a process once this process goes idle.
*
* If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
* have a preallocated process, this function does nothing.
*/
static void AllocateOnIdle();
/**
* Create a process right now.
*
* If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
* have a preallocated process, this function does nothing.
*/
static void AllocateNow();
/**
* Take the preallocated process, if we have one. If we don't have one, this
* returns null.
*
* If you call Take() twice in a row, the second call is guaranteed to return
* null.
*
* After you Take() the preallocated process, you need to call one of the
* Allocate* functions (or change the dom.ipc.processPrelaunch pref from
* false to true) before we'll create a new process.
*/
static already_AddRefed<ContentParent> Take();
private:
PreallocatedProcessManager();
DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManager);
};
} // namespace mozilla
#endif // defined mozilla_PreallocatedProcessManager_h

Просмотреть файл

@ -39,6 +39,7 @@ EXPORTS.mozilla.dom += [
]
EXPORTS.mozilla += [
'PreallocatedProcessManager.h',
'ProcessHangMonitor.h',
'ProcessHangMonitorIPC.h',
'ProcessPriorityManager.h',
@ -58,6 +59,7 @@ UNIFIED_SOURCES += [
'nsIContentChild.cpp',
'nsIContentParent.cpp',
'PermissionMessageUtils.cpp',
'PreallocatedProcessManager.cpp',
'ProcessPriorityManager.cpp',
'ScreenManagerParent.cpp',
'StructuredCloneData.cpp',

Просмотреть файл

@ -21,3 +21,5 @@ skip-if = !e10s
support-files =
blob_verify.sjs
!/dom/canvas/test/captureStream_common.js
[test_Preallocated.html]
skip-if = !e10s

Просмотреть файл

@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<!--
Test that the preallocated process starts up.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
function expectProcessCreated() {
return new Promise(resolve => {
function parentExpectProcessCreated() {
Components.utils.import('resource://gre/modules/Services.jsm');
let topic = "ipc:content-initializing";
let obs = { observe: function() {
Services.obs.removeObserver(obs, topic);
sendAsyncMessage('process-created');
}}
Services.obs.addObserver(obs, topic, /* weak = */ false);
}
let helper = SpecialPowers.loadChromeScript(parentExpectProcessCreated);
SimpleTest.registerCleanupFunction(function() { helper.destroy() });
helper.addMessageListener('process-created', resolve);
});
}
expectProcessCreated().then(() => {
ok(true, "Process creation detected.");
SimpleTest.finish();
});
// Kill existing preallocated process.
SpecialPowers.pushPrefEnv({'set':[["dom.ipc.processPrelaunch.enabled", false]]}).then(() => {
// Make sure we have the capacity to launch preallocated process.
SpecialPowers.pushPrefEnv({'set':[["dom.ipc.processCount", 100]]}).then(() => {
// Enable preallocated process and run the test.
SpecialPowers.pushPrefEnv({'set':[["dom.ipc.processPrelaunch.enabled", true]]});
});
});
</script>
</body>
</html>

Просмотреть файл

@ -915,6 +915,8 @@ ProcessPriorityToString(ProcessPriority aPriority)
switch (aPriority) {
case PROCESS_PRIORITY_MASTER:
return "MASTER";
case PROCESS_PRIORITY_PREALLOC:
return "PREALLOC";
case PROCESS_PRIORITY_FOREGROUND_HIGH:
return "FOREGROUND_HIGH";
case PROCESS_PRIORITY_FOREGROUND:

Просмотреть файл

@ -60,6 +60,9 @@ enum ProcessPriority {
PROCESS_PRIORITY_BACKGROUND,
PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE,
PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
// The special class for the preallocated process, high memory priority but
// low CPU priority.
PROCESS_PRIORITY_PREALLOC,
// Any priority greater than or equal to FOREGROUND is considered
// "foreground" for the purposes of priority testing, for example
// CurrentProcessIsForeground().