Bug 1305091 - Stop using content processes when they are running out of memory, r?mrbkap r?ksteuber data-r?francois
MozReview-Commit-ID: K67de7xbzqk
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1247,17 +1247,17 @@ ContentParent::ShutDownMessageManager()
CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
nullptr, nullptr, nullptr, nullptr);
mMessageManager->Disconnect();
mMessageManager = nullptr;
}
void
-ContentParent::MarkAsDead()
+ContentParent::MarkAsTroubled()
{
if (sBrowserContentParents) {
nsTArray<ContentParent*>* contentParents =
sBrowserContentParents->Get(mRemoteType);
if (contentParents) {
contentParents->RemoveElement(this);
if (contentParents->IsEmpty()) {
sBrowserContentParents->Remove(mRemoteType);
@@ -1271,17 +1271,23 @@ ContentParent::MarkAsDead()
if (sPrivateContent) {
sPrivateContent->RemoveElement(this);
if (!sPrivateContent->Length()) {
delete sPrivateContent;
sPrivateContent = nullptr;
}
}
-
+ mIsAvailable = false;
+}
+
+void
+ContentParent::MarkAsDead()
+{
+ MarkAsTroubled();
mIsAlive = false;
}
void
ContentParent::OnChannelError()
{
RefPtr<ContentParent> content(this);
PContentParent::OnChannelError();
@@ -1571,18 +1577,18 @@ ContentParent::ActorDestroy(ActorDestroy
bool
ContentParent::ShouldKeepProcessAlive() const
{
if (!sBrowserContentParents) {
return false;
}
- // If we have already been marked as dead, don't prevent shutdown.
- if (!IsAlive()) {
+ // If we have already been marked as troubled/dead, don't prevent shutdown.
+ if (!IsAvailable()) {
return false;
}
auto contentParents = sBrowserContentParents->Get(mRemoteType);
if (!contentParents) {
return false;
}
@@ -1716,16 +1722,17 @@ ContentParent::GetTestShellSingleton()
void
ContentParent::InitializeMembers()
{
mSubprocess = nullptr;
mChildID = gContentChildID++;
mGeolocationWatchID = -1;
mNumDestroyingTabs = 0;
+ mIsAvailable = true;
mIsAlive = true;
mSendPermissionUpdates = false;
mCalledClose = false;
mCalledKillHard = false;
mCreatedPairedMinidumps = false;
mShutdownPending = false;
mIPCOpen = true;
mHangMonitorActor = nullptr;
@@ -4569,19 +4576,24 @@ ContentParent::RecvNotifyPushSubscriptio
PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvNotifyLowMemory()
{
+ MarkAsTroubled();
+
+ Telemetry::ScalarAdd(Telemetry::ScalarID::DOM_CONTENTPROCESS_TROUBLED_DUE_TO_MEMORY, 1);
+
#ifdef MOZ_CRASHREPORTER
nsThread::SaveMemoryReportNearOOM(nsThread::ShouldSaveMemoryReport::kForceReport);
#endif
+
return IPC_OK();
}
/* static */ void
ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
BlobImpl* aBlobImpl,
nsIPrincipal* aPrincipal,
ContentParent* aIgnoreThisCP)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -323,16 +323,20 @@ public:
DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
bool aMarkedDestroying);
void ReportChildAlreadyBlocked();
bool RequestRunToCompletion();
+ bool IsAvailable() const
+ {
+ return mIsAvailable;
+ }
bool IsAlive() const override;
virtual bool IsForBrowser() const override
{
return mIsForBrowser;
}
GeckoChildProcessHost* Process() const
@@ -584,16 +588,24 @@ protected:
virtual void ActorDestroy(ActorDestroyReason why) override;
bool ShouldContinueFromReplyTimeout() override;
void OnVarChanged(const GfxVarUpdate& aVar) override;
void OnCompositorUnexpectedShutdown() override;
private:
+ /**
+ * A map of the remote content process type to a list of content parents
+ * currently available to host *new* tabs/frames of that type.
+ *
+ * If a content process is identified as troubled or dead, it will be
+ * removed from this list, but will still be in the sContentParents list for
+ * the GetAll/GetAllEvenIfDead APIs.
+ */
static nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* sBrowserContentParents;
static nsTArray<ContentParent*>* sPrivateContent;
static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
Monitor* aMonitor, bool* aDone);
static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
@@ -664,16 +676,22 @@ private:
/**
* Decide whether the process should be kept alive even when it would normally
* be shut down, for example when all its tabs are closed.
*/
bool ShouldKeepProcessAlive() const;
/**
+ * Mark this ContentParent as "troubled". This means that it is still alive,
+ * but it won't be returned for new tabs in GetNewOrUsedBrowserProcess.
+ */
+ void MarkAsTroubled();
+
+ /**
* Mark this ContentParent as dead for the purposes of Get*().
* This method is idempotent.
*/
void MarkAsDead();
/**
* How we will shut down this ContentParent and its subprocess.
*/
@@ -1112,20 +1130,22 @@ private:
// that even content processes that are 100% blocked (say from
// SIGSTOP), are still killed eventually. This task enforces that
// timer.
nsCOMPtr<nsITimer> mForceKillTimer;
// How many tabs we're waiting to finish their destruction
// sequence. Precisely, how many TabParents have called
// NotifyTabDestroying() but not called NotifyTabDestroyed().
int32_t mNumDestroyingTabs;
- // True only while this is ready to be used to host remote tabs.
- // This must not be used for new purposes after mIsAlive goes to
- // false, but some previously scheduled IPC traffic may still pass
- // through.
+ // True only while this process is in "good health" and may be used for
+ // new remote tabs.
+ bool mIsAvailable;
+ // True only while remote content is being actively used from this process.
+ // After mIsAlive goes to false, some previously scheduled IPC traffic may
+ // still pass through.
bool mIsAlive;
bool mSendPermissionUpdates;
bool mIsForBrowser;
// These variables track whether we've called Close() and KillHard() on our
// channel.
bool mCalledClose;
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -448,8 +448,25 @@ webrtc.nicer:
expires: "57"
kind: uint
notification_emails:
- webrtc-ice-telemetry-alerts@mozilla.com
release_channel_collection: opt-in
record_in_processes:
- 'main'
- 'content'
+
+# The following section contains content process base counters.
+dom.contentprocess:
+ troubled_due_to_memory:
+ bug_numbers:
+ - 1305091
+ description: >
+ The number of content processes that were marked as troubled because
+ it was running low on virtual memory.
+ expires: "58"
+ kind: uint
+ notification_emails:
+ - benjamin@smedbergs.us
+ - mconley@mozilla.com
+ release_channel_collection: opt-in
+ record_in_processes:
+ - 'main'