Loading dom/ipc/ContentChild.cpp +8 −15 Original line number Diff line number Diff line Loading @@ -2188,14 +2188,11 @@ void ContentChild::ActorDestroy(ActorDestroyReason why) { mIdleObservers.Clear(); if (mConsoleListener) { nsCOMPtr<nsIConsoleService> svc( do_GetService(NS_CONSOLESERVICE_CONTRACTID)); nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (svc) { svc->UnregisterListener(mConsoleListener); mConsoleListener->mChild = nullptr; } } mIsAlive = false; CrashReporterClient::DestroySingleton(); Loading Loading @@ -2593,21 +2590,17 @@ mozilla::ipc::IPCResult ContentChild::RecvAppInfo( mozilla::ipc::IPCResult ContentChild::RecvRemoteType( const nsCString& aRemoteType) { if (aRemoteType == mRemoteType) { // Allocation of preallocated processes that are still launching can // cause this return IPC_OK(); } if (!mRemoteType.IsVoid()) { // Preallocated processes are type PREALLOC_REMOTE_TYPE; they can become // anything except a File: process. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Changing remoteType of process %d from %s to %s", getpid(), mRemoteType.get(), aRemoteType.get())); // prealloc->anything (but file) or web->web allowed, and no-change // prealloc->anything (but file) or web->web allowed MOZ_RELEASE_ASSERT(aRemoteType != FILE_REMOTE_TYPE && mRemoteType == PREALLOC_REMOTE_TYPE); (mRemoteType == PREALLOC_REMOTE_TYPE || (mRemoteType == DEFAULT_REMOTE_TYPE && aRemoteType == DEFAULT_REMOTE_TYPE))); } else { // Initial setting of remote type. Either to 'prealloc' or the actual // final type (if we didn't use a preallocated process) Loading dom/ipc/ContentParent.cpp +60 −75 Original line number Diff line number Diff line Loading @@ -663,10 +663,13 @@ static const char* sObserverTopics[] = { // PreallocateProcess is called by the PreallocatedProcessManager. // ContentParent then takes this process back within GetNewOrUsedBrowserProcess. /*static*/ already_AddRefed<ContentParent> ContentParent::MakePreallocProcess() { /*static*/ RefPtr<ContentParent::LaunchPromise> ContentParent::PreallocateProcess() { RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE); return process.forget(); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocating process of type prealloc")); return process->LaunchSubprocessAsync(PROCESS_PRIORITY_PREALLOC); } /*static*/ Loading Loading @@ -908,7 +911,7 @@ static already_AddRefed<nsIPrincipal> CreateRemoteTypeIsolationPrincipal( /*static*/ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents, uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) { uint32_t aMaxContentParents, bool aPreferUsed) { #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED AutoRestore ar(sInProcessSelector); sInProcessSelector = true; Loading Loading @@ -983,7 +986,6 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( } // Try to take a preallocated process except for certain remote types. // Note: this process may not have finished launching yet RefPtr<ContentParent> preallocated; if (aRemoteType != FILE_REMOTE_TYPE && aRemoteType != EXTENSION_REMOTE_TYPE && // Bug 1638119 Loading @@ -994,33 +996,24 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( preallocated->AssertAlive(); if (profiler_thread_is_being_profiled()) { nsPrintfCString marker( "Assigned preallocated process %u%s", (unsigned int)preallocated->ChildID(), preallocated->IsLaunching() ? " (still launching)" : ""); nsPrintfCString marker("Assigned preallocated process %u", (unsigned int)preallocated->ChildID()); PROFILER_MARKER_TEXT("Process", DOM, {}, marker); } MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Adopted preallocated process %p for type %s%s", preallocated.get(), PromiseFlatCString(aRemoteType).get(), preallocated->IsLaunching() ? " (still launching)" : "")); ("Adopted preallocated process %p for type %s", preallocated.get(), PromiseFlatCString(aRemoteType).get())); // This ensures that the preallocator won't shut down the process once // it finishes starting preallocated->mRemoteType.Assign(aRemoteType); preallocated->mRemoteTypeIsolationPrincipal = CreateRemoteTypeIsolationPrincipal(aRemoteType); // Specialize this process for the appropriate remote type, and activate it. preallocated->mActivateTS = TimeStamp::Now(); preallocated->AddToPool(aContentParents); // rare, but will happen if (!preallocated->IsLaunching()) { // Specialize this process for the appropriate remote type, and activate // it. preallocated->mRemoteType.Assign(aRemoteType); preallocated->mRemoteTypeIsolationPrincipal = CreateRemoteTypeIsolationPrincipal(aRemoteType); Unused << preallocated->SendRemoteType(preallocated->mRemoteType); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { nsAutoString cpId; cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID())); Loading @@ -1028,7 +1021,6 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( "process-type-set", cpId.get()); preallocated->AssertAlive(); } } return preallocated.forget(); } Loading Loading @@ -1073,10 +1065,23 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess( } // Let's try and reuse an existing process. contentParent = GetUsedBrowserProcess( aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority); contentParent = GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents, aPreferUsed); if (contentParent) { // We have located a process. It may not have finished initializing, // this will be for the caller to handle. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: Used process %p (launching %d)", contentParent.get(), contentParent->IsLaunching())); contentParent->AssertAlive(); contentParent->StopRecycling(); if (aGroup) { aGroup->EnsureHostProcess(contentParent); } return contentParent.forget(); } if (!contentParent) { // No reusable process. Let's create and launch one. // The life cycle will be set to `LifecycleState::LAUNCHING`. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, Loading @@ -1089,22 +1094,18 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess( contentParent->LaunchSubprocessReject(); return nullptr; } // Store this process for future reuse. contentParent->AddToPool(contentParents); // Until the new process is ready let's not allow to start up any // preallocated processes. The blocker will be removed once we receive // the first idle message. contentParent->mIsAPreallocBlocker = true; PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent); // Store this process for future reuse. contentParent->AddToPool(contentParents); MOZ_LOG( ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: new immediate process %p", contentParent.get())); } // else we have an existing or preallocated process (which may be // still launching) MOZ_ASSERT(contentParent->IsLaunching()); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: new process %p", contentParent.get())); contentParent->AssertAlive(); contentParent->StopRecycling(); if (aGroup) { Loading Loading @@ -1146,8 +1147,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( ProcessPriority aPriority) { MOZ_DIAGNOSTIC_ASSERT(!IsDead()); if (!IsLaunching()) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: launched")); return LaunchPromise::CreateAndResolve(this, __func__); } Loading @@ -1162,8 +1161,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( GetCurrentSerialEventTarget(), __func__, [self = RefPtr{this}, aPriority] { if (self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: async, now launched")); self->mActivateTS = TimeStamp::Now(); return LaunchPromise::CreateAndResolve(self, __func__); } Loading @@ -1172,8 +1169,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( return LaunchPromise::CreateAndReject(LaunchError(), __func__); }, [self = RefPtr{this}] { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: async, rejected")); self->LaunchSubprocessReject(); return LaunchPromise::CreateAndReject(LaunchError(), __func__); }); Loading Loading @@ -1732,8 +1727,7 @@ void ContentParent::Init() { void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount, bool aSendShutDown) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose, ("MaybeBeginShutdown %p, %u vs %u", this, ManagedPBrowserParent().Count(), aExpectedBrowserCount)); ("MaybeBeginShutdown %p", this)); MOZ_ASSERT(NS_IsMainThread()); if (ManagedPBrowserParent().Count() != aExpectedBrowserCount || Loading Loading @@ -1783,8 +1777,6 @@ void ContentParent::MaybeAsyncSendShutDownMessage() { } void ContentParent::ShutDownProcess(ShutDownMethod aMethod) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("ShutDownProcess: %p", this)); // NB: must MarkAsDead() here so that this isn't accidentally // returned from Get*() while in the midst of shutdown. MarkAsDead(); Loading Loading @@ -2294,8 +2286,6 @@ bool ContentParent::ShouldKeepProcessAlive() { } void ContentParent::NotifyTabDestroying() { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("NotifyTabDestroying %p:", this)); // There can be more than one PBrowser for a given app process // because of popup windows. PBrowsers can also destroy // concurrently. When all the PBrowsers are destroying, kick off Loading Loading @@ -2569,8 +2559,6 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) { void ContentParent::LaunchSubprocessReject() { NS_ERROR("failed to launch child in the parent"); MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose, ("failed to launch child in the parent")); // Now that communication with the child is complete, we can cleanup // the preference serializer. mPrefSerializer = nullptr; Loading Loading @@ -3426,9 +3414,6 @@ mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() { // which we use as a good time to signal the PreallocatedProcessManager // that it can start allocating processes from now on. if (mIsAPreallocBlocker) { MOZ_LOG( ContentParent::GetLog(), LogLevel::Verbose, ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get())); PreallocatedProcessManager::RemoveBlocker(mRemoteType, this); mIsAPreallocBlocker = false; } Loading Loading @@ -4094,9 +4079,9 @@ void ContentParent::KillHard(const char* aReason) { if (mSubprocess) { MOZ_LOG( ContentParent::GetLog(), LogLevel::Verbose, ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle " ("KillHard Subprocess: ContentParent %p mSubprocess %p handle " "%" PRIuPTR, aReason, this, mSubprocess, this, mSubprocess, mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1)); mSubprocess->SetAlreadyDead(); } Loading dom/ipc/ContentParent.h +3 −3 Original line number Diff line number Diff line Loading @@ -152,9 +152,9 @@ class ContentParent final static LogModule* GetLog(); /** * Create a ContentParent suitable for use later as a content process. * Create a subprocess suitable for use later as a content process. */ static already_AddRefed<ContentParent> MakePreallocProcess(); static RefPtr<LaunchPromise> PreallocateProcess(); /** * Start up the content-process machinery. This might include Loading Loading @@ -1446,7 +1446,7 @@ class ContentParent final // Return an existing ContentParent if possible. Otherwise, `nullptr`. static already_AddRefed<ContentParent> GetUsedBrowserProcess( const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents, uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority); uint32_t aMaxContentParents, bool aPreferUsed); void AddToPool(nsTArray<ContentParent*>&); void RemoveFromPool(nsTArray<ContentParent*>&); Loading dom/ipc/PreallocatedProcessManager.cpp +71 −70 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ #include "ProcessPriorityManager.h" #include "nsServiceManagerUtils.h" #include "nsIXULRuntime.h" #include "nsTArray.h" #include "prsystem.h" #include <deque> using namespace mozilla::hal; using namespace mozilla::dom; Loading Loading @@ -68,12 +68,15 @@ class PreallocatedProcessManagerImpl final : public nsIObserver { void Disable(); void CloseProcesses(); bool IsEmpty() const { return mPreallocatedProcesses.IsEmpty(); } bool IsEmpty() const { return mPreallocatedProcesses.empty() && !mLaunchInProgress; } bool mEnabled; static bool sShutdown; bool mLaunchInProgress; uint32_t mNumberPreallocs; AutoTArray<RefPtr<ContentParent>, 3> mPreallocatedProcesses; std::deque<RefPtr<ContentParent>> mPreallocatedProcesses; // Even if we have multiple PreallocatedProcessManagerImpls, we'll have // one blocker counter static uint32_t sNumBlockers; Loading Loading @@ -109,12 +112,12 @@ PreallocatedProcessManagerImpl* PreallocatedProcessManagerImpl::Singleton() { NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver) PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl() : mEnabled(false), mNumberPreallocs(1) {} : mEnabled(false), mLaunchInProgress(false), mNumberPreallocs(1) {} PreallocatedProcessManagerImpl::~PreallocatedProcessManagerImpl() { // Note: mPreallocatedProcesses may not be null, but all processes should // be dead (IsDead==true). We block Erase() when our observer sees // shutdown starting. // This shouldn't happen, because the promise callbacks should // hold strong references, but let't make absolutely sure: MOZ_RELEASE_ASSERT(!mLaunchInProgress); } void PreallocatedProcessManagerImpl::Init() { Loading Loading @@ -185,7 +188,7 @@ void PreallocatedProcessManagerImpl::RereadPrefs() { if (number >= 0) { Enable(number); // We have one prealloc queue for all types except File now if (static_cast<uint64_t>(number) < mPreallocatedProcesses.Length()) { if (static_cast<uint64_t>(number) < mPreallocatedProcesses.size()) { CloseProcesses(); } } Loading @@ -200,36 +203,31 @@ already_AddRefed<ContentParent> PreallocatedProcessManagerImpl::Take( return nullptr; } RefPtr<ContentParent> process; if (!IsEmpty()) { process = mPreallocatedProcesses.ElementAt(0); mPreallocatedProcesses.RemoveElementAt(0); if (!mPreallocatedProcesses.empty()) { process = mPreallocatedProcesses.front().forget(); mPreallocatedProcesses.pop_front(); // holds a nullptr // Don't set the priority to FOREGROUND here, since it may not have // finished starting ProcessPriorityManager::SetProcessPriority(process, PROCESS_PRIORITY_FOREGROUND); // We took a preallocated process. Let's try to start up a new one // soon. ContentParent* last = mPreallocatedProcesses.SafeLastElement(nullptr); // There could be a launching process that isn't the last, but that's // ok (and unlikely) if (!last || !last->IsLaunching()) { AllocateAfterDelay(); } MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Use prealloc process %p%s, %lu available", process.get(), process->IsLaunching() ? " (still launching)" : "", (unsigned long)mPreallocatedProcesses.Length())); ("Use prealloc process %p", process.get())); } if (process && !process->IsLaunching()) { ProcessPriorityManager::SetProcessPriority(process, PROCESS_PRIORITY_FOREGROUND); } // else this will get set by the caller when they call InitInternal() return process.forget(); } void PreallocatedProcessManagerImpl::Erase(ContentParent* aParent) { (void)mPreallocatedProcesses.RemoveElement(aParent); // Ensure this ContentParent isn't cached for (auto it = mPreallocatedProcesses.begin(); it != mPreallocatedProcesses.end(); it++) { if (*it == aParent) { mPreallocatedProcesses.erase(it); break; } } } void PreallocatedProcessManagerImpl::Enable(uint32_t aProcesses) { Loading Loading @@ -274,7 +272,7 @@ void PreallocatedProcessManagerImpl::RemoveBlocker(ContentParent* aParent) { bool PreallocatedProcessManagerImpl::CanAllocate() { return mEnabled && sNumBlockers == 0 && mPreallocatedProcesses.Length() < mNumberPreallocs && !sShutdown && mPreallocatedProcesses.size() < mNumberPreallocs && !sShutdown && (FissionAutostart() || !ContentParent::IsMaxProcessCountReached(DEFAULT_REMOTE_TYPE)); } Loading Loading @@ -317,19 +315,15 @@ void PreallocatedProcessManagerImpl::AllocateNow() { return; } RefPtr<ContentParent> process = ContentParent::MakePreallocProcess(); mPreallocatedProcesses.AppendElement(process); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocated = %lu of %d processes", (unsigned long)mPreallocatedProcesses.Length(), mNumberPreallocs)); RefPtr<PreallocatedProcessManagerImpl> self(this); process->LaunchSubprocessAsync(PROCESS_PRIORITY_PREALLOC) ->Then( mLaunchInProgress = true; ContentParent::PreallocateProcess()->Then( GetCurrentSerialEventTarget(), __func__, [self, this, process](const RefPtr<ContentParent>&) { [self, this](const RefPtr<ContentParent>& process) { mLaunchInProgress = false; if (process->IsDead()) { Erase(process); // Process died in startup (before we could add it). If it // dies after this, MarkAsDead() will Erase() this entry. // Shouldn't be in the sBrowserContentParents, so we don't need Loading @@ -338,24 +332,31 @@ void PreallocatedProcessManagerImpl::AllocateNow() { // causing them to consistently fail; if everything is ok on the // next allocation request we'll kick off creation. } else { // Continue prestarting processes if needed if (CanAllocate()) { if (mPreallocatedProcesses.Length() < mNumberPreallocs) { // slight perf reason for push_back - while the cpu cache // probably has stack/etc associated with the most recent // process created, we don't know that it has finished startup. // If we added it to the queue on completion of startup, we // could push_front it, but that would require a bunch more // logic. mPreallocatedProcesses.push_back(process); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocated = %lu of %d processes", (unsigned long)mPreallocatedProcesses.size(), mNumberPreallocs)); // Continue prestarting processes if needed if (mPreallocatedProcesses.size() < mNumberPreallocs) { AllocateOnIdle(); } } else if (!mEnabled || sShutdown) { // if this has a remote type set, it's been allocated for use // already if (process->mRemoteType == PREALLOC_REMOTE_TYPE) { // This will Erase() it process->ShutDownProcess( ContentParent::SEND_SHUTDOWN_MESSAGE); } } else { process->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE); } } }, [self, this, process](ContentParent::LaunchError) { Erase(process); [self, this](ContentParent::LaunchError err) { mLaunchInProgress = false; }); } Loading @@ -369,9 +370,9 @@ void PreallocatedProcessManagerImpl::Disable() { } void PreallocatedProcessManagerImpl::CloseProcesses() { while (!IsEmpty()) { RefPtr<ContentParent> process(mPreallocatedProcesses.ElementAt(0)); mPreallocatedProcesses.RemoveElementAt(0); while (!mPreallocatedProcesses.empty()) { RefPtr<ContentParent> process(mPreallocatedProcesses.front().forget()); mPreallocatedProcesses.pop_front(); process->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE); // drop ref and let it free } Loading Loading
dom/ipc/ContentChild.cpp +8 −15 Original line number Diff line number Diff line Loading @@ -2188,14 +2188,11 @@ void ContentChild::ActorDestroy(ActorDestroyReason why) { mIdleObservers.Clear(); if (mConsoleListener) { nsCOMPtr<nsIConsoleService> svc( do_GetService(NS_CONSOLESERVICE_CONTRACTID)); nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (svc) { svc->UnregisterListener(mConsoleListener); mConsoleListener->mChild = nullptr; } } mIsAlive = false; CrashReporterClient::DestroySingleton(); Loading Loading @@ -2593,21 +2590,17 @@ mozilla::ipc::IPCResult ContentChild::RecvAppInfo( mozilla::ipc::IPCResult ContentChild::RecvRemoteType( const nsCString& aRemoteType) { if (aRemoteType == mRemoteType) { // Allocation of preallocated processes that are still launching can // cause this return IPC_OK(); } if (!mRemoteType.IsVoid()) { // Preallocated processes are type PREALLOC_REMOTE_TYPE; they can become // anything except a File: process. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Changing remoteType of process %d from %s to %s", getpid(), mRemoteType.get(), aRemoteType.get())); // prealloc->anything (but file) or web->web allowed, and no-change // prealloc->anything (but file) or web->web allowed MOZ_RELEASE_ASSERT(aRemoteType != FILE_REMOTE_TYPE && mRemoteType == PREALLOC_REMOTE_TYPE); (mRemoteType == PREALLOC_REMOTE_TYPE || (mRemoteType == DEFAULT_REMOTE_TYPE && aRemoteType == DEFAULT_REMOTE_TYPE))); } else { // Initial setting of remote type. Either to 'prealloc' or the actual // final type (if we didn't use a preallocated process) Loading
dom/ipc/ContentParent.cpp +60 −75 Original line number Diff line number Diff line Loading @@ -663,10 +663,13 @@ static const char* sObserverTopics[] = { // PreallocateProcess is called by the PreallocatedProcessManager. // ContentParent then takes this process back within GetNewOrUsedBrowserProcess. /*static*/ already_AddRefed<ContentParent> ContentParent::MakePreallocProcess() { /*static*/ RefPtr<ContentParent::LaunchPromise> ContentParent::PreallocateProcess() { RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE); return process.forget(); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocating process of type prealloc")); return process->LaunchSubprocessAsync(PROCESS_PRIORITY_PREALLOC); } /*static*/ Loading Loading @@ -908,7 +911,7 @@ static already_AddRefed<nsIPrincipal> CreateRemoteTypeIsolationPrincipal( /*static*/ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents, uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) { uint32_t aMaxContentParents, bool aPreferUsed) { #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED AutoRestore ar(sInProcessSelector); sInProcessSelector = true; Loading Loading @@ -983,7 +986,6 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( } // Try to take a preallocated process except for certain remote types. // Note: this process may not have finished launching yet RefPtr<ContentParent> preallocated; if (aRemoteType != FILE_REMOTE_TYPE && aRemoteType != EXTENSION_REMOTE_TYPE && // Bug 1638119 Loading @@ -994,33 +996,24 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( preallocated->AssertAlive(); if (profiler_thread_is_being_profiled()) { nsPrintfCString marker( "Assigned preallocated process %u%s", (unsigned int)preallocated->ChildID(), preallocated->IsLaunching() ? " (still launching)" : ""); nsPrintfCString marker("Assigned preallocated process %u", (unsigned int)preallocated->ChildID()); PROFILER_MARKER_TEXT("Process", DOM, {}, marker); } MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Adopted preallocated process %p for type %s%s", preallocated.get(), PromiseFlatCString(aRemoteType).get(), preallocated->IsLaunching() ? " (still launching)" : "")); ("Adopted preallocated process %p for type %s", preallocated.get(), PromiseFlatCString(aRemoteType).get())); // This ensures that the preallocator won't shut down the process once // it finishes starting preallocated->mRemoteType.Assign(aRemoteType); preallocated->mRemoteTypeIsolationPrincipal = CreateRemoteTypeIsolationPrincipal(aRemoteType); // Specialize this process for the appropriate remote type, and activate it. preallocated->mActivateTS = TimeStamp::Now(); preallocated->AddToPool(aContentParents); // rare, but will happen if (!preallocated->IsLaunching()) { // Specialize this process for the appropriate remote type, and activate // it. preallocated->mRemoteType.Assign(aRemoteType); preallocated->mRemoteTypeIsolationPrincipal = CreateRemoteTypeIsolationPrincipal(aRemoteType); Unused << preallocated->SendRemoteType(preallocated->mRemoteType); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { nsAutoString cpId; cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID())); Loading @@ -1028,7 +1021,6 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess( "process-type-set", cpId.get()); preallocated->AssertAlive(); } } return preallocated.forget(); } Loading Loading @@ -1073,10 +1065,23 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess( } // Let's try and reuse an existing process. contentParent = GetUsedBrowserProcess( aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority); contentParent = GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents, aPreferUsed); if (contentParent) { // We have located a process. It may not have finished initializing, // this will be for the caller to handle. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: Used process %p (launching %d)", contentParent.get(), contentParent->IsLaunching())); contentParent->AssertAlive(); contentParent->StopRecycling(); if (aGroup) { aGroup->EnsureHostProcess(contentParent); } return contentParent.forget(); } if (!contentParent) { // No reusable process. Let's create and launch one. // The life cycle will be set to `LifecycleState::LAUNCHING`. MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, Loading @@ -1089,22 +1094,18 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess( contentParent->LaunchSubprocessReject(); return nullptr; } // Store this process for future reuse. contentParent->AddToPool(contentParents); // Until the new process is ready let's not allow to start up any // preallocated processes. The blocker will be removed once we receive // the first idle message. contentParent->mIsAPreallocBlocker = true; PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent); // Store this process for future reuse. contentParent->AddToPool(contentParents); MOZ_LOG( ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: new immediate process %p", contentParent.get())); } // else we have an existing or preallocated process (which may be // still launching) MOZ_ASSERT(contentParent->IsLaunching()); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("GetNewOrUsedProcess: new process %p", contentParent.get())); contentParent->AssertAlive(); contentParent->StopRecycling(); if (aGroup) { Loading Loading @@ -1146,8 +1147,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( ProcessPriority aPriority) { MOZ_DIAGNOSTIC_ASSERT(!IsDead()); if (!IsLaunching()) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: launched")); return LaunchPromise::CreateAndResolve(this, __func__); } Loading @@ -1162,8 +1161,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( GetCurrentSerialEventTarget(), __func__, [self = RefPtr{this}, aPriority] { if (self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: async, now launched")); self->mActivateTS = TimeStamp::Now(); return LaunchPromise::CreateAndResolve(self, __func__); } Loading @@ -1172,8 +1169,6 @@ RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync( return LaunchPromise::CreateAndReject(LaunchError(), __func__); }, [self = RefPtr{this}] { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("WaitForLaunchAsync: async, rejected")); self->LaunchSubprocessReject(); return LaunchPromise::CreateAndReject(LaunchError(), __func__); }); Loading Loading @@ -1732,8 +1727,7 @@ void ContentParent::Init() { void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount, bool aSendShutDown) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose, ("MaybeBeginShutdown %p, %u vs %u", this, ManagedPBrowserParent().Count(), aExpectedBrowserCount)); ("MaybeBeginShutdown %p", this)); MOZ_ASSERT(NS_IsMainThread()); if (ManagedPBrowserParent().Count() != aExpectedBrowserCount || Loading Loading @@ -1783,8 +1777,6 @@ void ContentParent::MaybeAsyncSendShutDownMessage() { } void ContentParent::ShutDownProcess(ShutDownMethod aMethod) { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("ShutDownProcess: %p", this)); // NB: must MarkAsDead() here so that this isn't accidentally // returned from Get*() while in the midst of shutdown. MarkAsDead(); Loading Loading @@ -2294,8 +2286,6 @@ bool ContentParent::ShouldKeepProcessAlive() { } void ContentParent::NotifyTabDestroying() { MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("NotifyTabDestroying %p:", this)); // There can be more than one PBrowser for a given app process // because of popup windows. PBrowsers can also destroy // concurrently. When all the PBrowsers are destroying, kick off Loading Loading @@ -2569,8 +2559,6 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) { void ContentParent::LaunchSubprocessReject() { NS_ERROR("failed to launch child in the parent"); MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose, ("failed to launch child in the parent")); // Now that communication with the child is complete, we can cleanup // the preference serializer. mPrefSerializer = nullptr; Loading Loading @@ -3426,9 +3414,6 @@ mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() { // which we use as a good time to signal the PreallocatedProcessManager // that it can start allocating processes from now on. if (mIsAPreallocBlocker) { MOZ_LOG( ContentParent::GetLog(), LogLevel::Verbose, ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get())); PreallocatedProcessManager::RemoveBlocker(mRemoteType, this); mIsAPreallocBlocker = false; } Loading Loading @@ -4094,9 +4079,9 @@ void ContentParent::KillHard(const char* aReason) { if (mSubprocess) { MOZ_LOG( ContentParent::GetLog(), LogLevel::Verbose, ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle " ("KillHard Subprocess: ContentParent %p mSubprocess %p handle " "%" PRIuPTR, aReason, this, mSubprocess, this, mSubprocess, mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1)); mSubprocess->SetAlreadyDead(); } Loading
dom/ipc/ContentParent.h +3 −3 Original line number Diff line number Diff line Loading @@ -152,9 +152,9 @@ class ContentParent final static LogModule* GetLog(); /** * Create a ContentParent suitable for use later as a content process. * Create a subprocess suitable for use later as a content process. */ static already_AddRefed<ContentParent> MakePreallocProcess(); static RefPtr<LaunchPromise> PreallocateProcess(); /** * Start up the content-process machinery. This might include Loading Loading @@ -1446,7 +1446,7 @@ class ContentParent final // Return an existing ContentParent if possible. Otherwise, `nullptr`. static already_AddRefed<ContentParent> GetUsedBrowserProcess( const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents, uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority); uint32_t aMaxContentParents, bool aPreferUsed); void AddToPool(nsTArray<ContentParent*>&); void RemoveFromPool(nsTArray<ContentParent*>&); Loading
dom/ipc/PreallocatedProcessManager.cpp +71 −70 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ #include "ProcessPriorityManager.h" #include "nsServiceManagerUtils.h" #include "nsIXULRuntime.h" #include "nsTArray.h" #include "prsystem.h" #include <deque> using namespace mozilla::hal; using namespace mozilla::dom; Loading Loading @@ -68,12 +68,15 @@ class PreallocatedProcessManagerImpl final : public nsIObserver { void Disable(); void CloseProcesses(); bool IsEmpty() const { return mPreallocatedProcesses.IsEmpty(); } bool IsEmpty() const { return mPreallocatedProcesses.empty() && !mLaunchInProgress; } bool mEnabled; static bool sShutdown; bool mLaunchInProgress; uint32_t mNumberPreallocs; AutoTArray<RefPtr<ContentParent>, 3> mPreallocatedProcesses; std::deque<RefPtr<ContentParent>> mPreallocatedProcesses; // Even if we have multiple PreallocatedProcessManagerImpls, we'll have // one blocker counter static uint32_t sNumBlockers; Loading Loading @@ -109,12 +112,12 @@ PreallocatedProcessManagerImpl* PreallocatedProcessManagerImpl::Singleton() { NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver) PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl() : mEnabled(false), mNumberPreallocs(1) {} : mEnabled(false), mLaunchInProgress(false), mNumberPreallocs(1) {} PreallocatedProcessManagerImpl::~PreallocatedProcessManagerImpl() { // Note: mPreallocatedProcesses may not be null, but all processes should // be dead (IsDead==true). We block Erase() when our observer sees // shutdown starting. // This shouldn't happen, because the promise callbacks should // hold strong references, but let't make absolutely sure: MOZ_RELEASE_ASSERT(!mLaunchInProgress); } void PreallocatedProcessManagerImpl::Init() { Loading Loading @@ -185,7 +188,7 @@ void PreallocatedProcessManagerImpl::RereadPrefs() { if (number >= 0) { Enable(number); // We have one prealloc queue for all types except File now if (static_cast<uint64_t>(number) < mPreallocatedProcesses.Length()) { if (static_cast<uint64_t>(number) < mPreallocatedProcesses.size()) { CloseProcesses(); } } Loading @@ -200,36 +203,31 @@ already_AddRefed<ContentParent> PreallocatedProcessManagerImpl::Take( return nullptr; } RefPtr<ContentParent> process; if (!IsEmpty()) { process = mPreallocatedProcesses.ElementAt(0); mPreallocatedProcesses.RemoveElementAt(0); if (!mPreallocatedProcesses.empty()) { process = mPreallocatedProcesses.front().forget(); mPreallocatedProcesses.pop_front(); // holds a nullptr // Don't set the priority to FOREGROUND here, since it may not have // finished starting ProcessPriorityManager::SetProcessPriority(process, PROCESS_PRIORITY_FOREGROUND); // We took a preallocated process. Let's try to start up a new one // soon. ContentParent* last = mPreallocatedProcesses.SafeLastElement(nullptr); // There could be a launching process that isn't the last, but that's // ok (and unlikely) if (!last || !last->IsLaunching()) { AllocateAfterDelay(); } MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Use prealloc process %p%s, %lu available", process.get(), process->IsLaunching() ? " (still launching)" : "", (unsigned long)mPreallocatedProcesses.Length())); ("Use prealloc process %p", process.get())); } if (process && !process->IsLaunching()) { ProcessPriorityManager::SetProcessPriority(process, PROCESS_PRIORITY_FOREGROUND); } // else this will get set by the caller when they call InitInternal() return process.forget(); } void PreallocatedProcessManagerImpl::Erase(ContentParent* aParent) { (void)mPreallocatedProcesses.RemoveElement(aParent); // Ensure this ContentParent isn't cached for (auto it = mPreallocatedProcesses.begin(); it != mPreallocatedProcesses.end(); it++) { if (*it == aParent) { mPreallocatedProcesses.erase(it); break; } } } void PreallocatedProcessManagerImpl::Enable(uint32_t aProcesses) { Loading Loading @@ -274,7 +272,7 @@ void PreallocatedProcessManagerImpl::RemoveBlocker(ContentParent* aParent) { bool PreallocatedProcessManagerImpl::CanAllocate() { return mEnabled && sNumBlockers == 0 && mPreallocatedProcesses.Length() < mNumberPreallocs && !sShutdown && mPreallocatedProcesses.size() < mNumberPreallocs && !sShutdown && (FissionAutostart() || !ContentParent::IsMaxProcessCountReached(DEFAULT_REMOTE_TYPE)); } Loading Loading @@ -317,19 +315,15 @@ void PreallocatedProcessManagerImpl::AllocateNow() { return; } RefPtr<ContentParent> process = ContentParent::MakePreallocProcess(); mPreallocatedProcesses.AppendElement(process); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocated = %lu of %d processes", (unsigned long)mPreallocatedProcesses.Length(), mNumberPreallocs)); RefPtr<PreallocatedProcessManagerImpl> self(this); process->LaunchSubprocessAsync(PROCESS_PRIORITY_PREALLOC) ->Then( mLaunchInProgress = true; ContentParent::PreallocateProcess()->Then( GetCurrentSerialEventTarget(), __func__, [self, this, process](const RefPtr<ContentParent>&) { [self, this](const RefPtr<ContentParent>& process) { mLaunchInProgress = false; if (process->IsDead()) { Erase(process); // Process died in startup (before we could add it). If it // dies after this, MarkAsDead() will Erase() this entry. // Shouldn't be in the sBrowserContentParents, so we don't need Loading @@ -338,24 +332,31 @@ void PreallocatedProcessManagerImpl::AllocateNow() { // causing them to consistently fail; if everything is ok on the // next allocation request we'll kick off creation. } else { // Continue prestarting processes if needed if (CanAllocate()) { if (mPreallocatedProcesses.Length() < mNumberPreallocs) { // slight perf reason for push_back - while the cpu cache // probably has stack/etc associated with the most recent // process created, we don't know that it has finished startup. // If we added it to the queue on completion of startup, we // could push_front it, but that would require a bunch more // logic. mPreallocatedProcesses.push_back(process); MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, ("Preallocated = %lu of %d processes", (unsigned long)mPreallocatedProcesses.size(), mNumberPreallocs)); // Continue prestarting processes if needed if (mPreallocatedProcesses.size() < mNumberPreallocs) { AllocateOnIdle(); } } else if (!mEnabled || sShutdown) { // if this has a remote type set, it's been allocated for use // already if (process->mRemoteType == PREALLOC_REMOTE_TYPE) { // This will Erase() it process->ShutDownProcess( ContentParent::SEND_SHUTDOWN_MESSAGE); } } else { process->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE); } } }, [self, this, process](ContentParent::LaunchError) { Erase(process); [self, this](ContentParent::LaunchError err) { mLaunchInProgress = false; }); } Loading @@ -369,9 +370,9 @@ void PreallocatedProcessManagerImpl::Disable() { } void PreallocatedProcessManagerImpl::CloseProcesses() { while (!IsEmpty()) { RefPtr<ContentParent> process(mPreallocatedProcesses.ElementAt(0)); mPreallocatedProcesses.RemoveElementAt(0); while (!mPreallocatedProcesses.empty()) { RefPtr<ContentParent> process(mPreallocatedProcesses.front().forget()); mPreallocatedProcesses.pop_front(); process->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE); // drop ref and let it free } Loading