Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/ipc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  PreallocatedProcessManager.cpp   Sprache: C

 
/* -*- 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/AppShutdown.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/StaticPrefs_dom.h"
#include "nsIPropertyBag2.h"
#include "ProcessPriorityManager.h"
#include "nsServiceManagerUtils.h"
#include "nsIXULRuntime.h"
#include "nsTArray.h"
#include "prsystem.h"

using namespace mozilla::hal;
using namespace mozilla::dom;

namespace mozilla {
/**
 * This singleton class implements the static methods on
 * PreallocatedProcessManager.
 */

class PreallocatedProcessManagerImpl final : public nsIObserver {
  friend class PreallocatedProcessManager;

 public:
  static PreallocatedProcessManagerImpl* Singleton();

  NS_DECL_ISUPPORTS
  NS_DECL_NSIOBSERVER

  // See comments on PreallocatedProcessManager for these methods.
  void AddBlocker(ContentParent* aParent);
  void RemoveBlocker(ContentParent* aParent);
  UniqueContentParentKeepAlive Take(const nsACString& aRemoteType);
  void Erase(ContentParent* aParent);

 private:
  static const charconst kObserverTopics[];

  static StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;

  PreallocatedProcessManagerImpl();
  ~PreallocatedProcessManagerImpl();
  PreallocatedProcessManagerImpl(const PreallocatedProcessManagerImpl&) =
      delete;

  const PreallocatedProcessManagerImpl& operator=(
      const PreallocatedProcessManagerImpl&) = delete;

  void Init();

  bool CanAllocate();
  void AllocateAfterDelay(bool aStartup = false);
  void AllocateOnIdle();
  void AllocateNow();

  void RereadPrefs();
  void Enable(uint32_t aProcesses);
  void Disable();
  void CloseProcesses();

  bool IsEmpty() const { return mPreallocatedProcesses.IsEmpty(); }
  static bool IsShutdown() {
    return AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
  }
  bool IsEnabled() { return mEnabled && !IsShutdown(); }

  bool mEnabled;
  uint32_t mNumberPreallocs;
  AutoTArray<UniqueContentParentKeepAlive, 3> mPreallocatedProcesses;
  // Even if we have multiple PreallocatedProcessManagerImpls, we'll have
  // one blocker counter
  static uint32_t sNumBlockers;
  TimeStamp mBlockingStartTime;
};

/* static */
uint32_t PreallocatedProcessManagerImpl::sNumBlockers = 0;

const charconst PreallocatedProcessManagerImpl::kObserverTopics[] = {
    "memory-pressure",
    "profile-change-teardown",
    NS_XPCOM_SHUTDOWN_OBSERVER_ID,
};

/* static */
StaticRefPtr<PreallocatedProcessManagerImpl>
    PreallocatedProcessManagerImpl::sSingleton;

/* static */
PreallocatedProcessManagerImpl* PreallocatedProcessManagerImpl::Singleton() {
  MOZ_ASSERT(NS_IsMainThread());
  if (!sSingleton) {
    sSingleton = new PreallocatedProcessManagerImpl;
    sSingleton->Init();
    ClearOnShutdown(&sSingleton);
  }
  return sSingleton;
  //  PreallocatedProcessManagers live until shutdown
}

NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)

PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
    : mEnabled(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.
}

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");
  // A StaticPref, but we need to adjust the number of preallocated processes
  // if the value goes up or down, so we need to run code on change.
  Preferences::AddStrongObserver(this,
                                 "dom.ipc.processPrelaunch.fission.number");

  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  MOZ_ASSERT(os);
  for (auto topic : kObserverTopics) {
    os->AddObserver(this, topic, /* ownsWeak */ false);
  }
  RereadPrefs();
}

NS_IMETHODIMP
PreallocatedProcessManagerImpl::Observe(nsISupports* aSubject,
                                        const char* aTopic,
                                        const char16_t* aData) {
  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) ||
             !strcmp("profile-change-teardown", aTopic)) {
    Preferences::RemoveObserver(this"dom.ipc.processPrelaunch.enabled");
    Preferences::RemoveObserver(this"dom.ipc.processCount");
    Preferences::RemoveObserver(this,
                                "dom.ipc.processPrelaunch.fission.number");

    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
    MOZ_ASSERT(os);
    for (auto topic : kObserverTopics) {
      os->RemoveObserver(this, topic);
    }
  } else if (!strcmp("memory-pressure", aTopic)) {
    CloseProcesses();
  } else {
    MOZ_ASSERT_UNREACHABLE("Unknown topic");
  }

  return NS_OK;
}

void PreallocatedProcessManagerImpl::RereadPrefs() {
  if (mozilla::BrowserTabsRemoteAutostart() &&
      Preferences::GetBool("dom.ipc.processPrelaunch.enabled")) {
    int32_t number = 1;
    if (mozilla::FissionAutostart()) {
      number = StaticPrefs::dom_ipc_processPrelaunch_fission_number();
      // limit preallocated processes on low-mem machines
      PRUint64 bytes = PR_GetPhysicalMemorySize();
      if (bytes > 0 &&
          bytes <=
              StaticPrefs::dom_ipc_processPrelaunch_lowmem_mb() * 1024 * 1024) {
        number = 1;
      }
    }
    if (number >= 0) {
      Enable(number);
      // We have one prealloc queue for all types except File now
      if (static_cast<uint64_t>(number) < mPreallocatedProcesses.Length()) {
        CloseProcesses();
      }
    }
  } else {
    Disable();
  }
}

UniqueContentParentKeepAlive PreallocatedProcessManagerImpl::Take(
    const nsACString& aRemoteType) {
  if (!IsEnabled()) {
    return nullptr;
  }
  UniqueContentParentKeepAlive process;
  if (!IsEmpty()) {
    process = std::move(mPreallocatedProcesses.ElementAt(0));
    mPreallocatedProcesses.RemoveElementAt(0);

    // Don't set the priority to FOREGROUND here, since it may not have
    // finished starting

    // We took a preallocated process. Let's try to start up a new one
    // soon.
    ContentParent* last = mPreallocatedProcesses.SafeLastElement(nullptr).get();
    // 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()));
  }
  if (process && !process->IsLaunching()) {
    ProcessPriorityManager::SetProcessPriority(process.get(),
                                               PROCESS_PRIORITY_FOREGROUND);
  }  // else this will get set by the caller when they call InitInternal()

  return process;
}

void PreallocatedProcessManagerImpl::Erase(ContentParent* aParent) {
  (void)mPreallocatedProcesses.RemoveElement(aParent);
}

void PreallocatedProcessManagerImpl::Enable(uint32_t aProcesses) {
  mNumberPreallocs = aProcesses;
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("Enabling preallocation: %u", aProcesses));
  if (mEnabled || IsShutdown()) {
    return;
  }

  mEnabled = true;
  AllocateAfterDelay(/* aStartup */ true);
}

void PreallocatedProcessManagerImpl::AddBlocker(ContentParent* aParent) {
  if (sNumBlockers == 0) {
    mBlockingStartTime = TimeStamp::Now();
  }
  sNumBlockers++;
}

void PreallocatedProcessManagerImpl::RemoveBlocker(ContentParent* aParent) {
  // This used to assert that the blocker existed, but preallocated
  // processes aren't blockers anymore because it's not useful and
  // interferes with async launch, and it's simpler if content
  // processes don't need to remember whether they were preallocated.

  MOZ_DIAGNOSTIC_ASSERT(sNumBlockers > 0);
  sNumBlockers--;
  if (sNumBlockers == 0) {
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
            ("Blocked preallocation for %fms",
             (TimeStamp::Now() - mBlockingStartTime).ToMilliseconds()));
    PROFILER_MARKER_TEXT("Process", DOM,
                         MarkerTiming::IntervalUntilNowFrom(mBlockingStartTime),
                         "Blocked preallocation");
    if (IsEmpty()) {
      AllocateAfterDelay();
    }
  }
}

bool PreallocatedProcessManagerImpl::CanAllocate() {
  return IsEnabled() && sNumBlockers == 0 &&
         mPreallocatedProcesses.Length() < mNumberPreallocs && !IsShutdown() &&
         (FissionAutostart() ||
          !ContentParent::IsMaxProcessCountReached(DEFAULT_REMOTE_TYPE));
}

void PreallocatedProcessManagerImpl::AllocateAfterDelay(bool aStartup) {
  if (!IsEnabled()) {
    return;
  }
  long delay = aStartup ? StaticPrefs::dom_ipc_processPrelaunch_startupDelayMs()
                        : StaticPrefs::dom_ipc_processPrelaunch_delayMs();
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("Starting delayed process start, delay=%ld", delay));
  NS_DelayedDispatchToCurrentThread(
      NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateOnIdle"this,
                        &PreallocatedProcessManagerImpl::AllocateOnIdle),
      delay);
}

void PreallocatedProcessManagerImpl::AllocateOnIdle() {
  if (!IsEnabled()) {
    return;
  }

  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("Starting process allocate on idle"));
  NS_DispatchToCurrentThreadQueue(
      NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateNow"this,
                        &PreallocatedProcessManagerImpl::AllocateNow),
      EventQueuePriority::Idle);
}

void PreallocatedProcessManagerImpl::AllocateNow() {
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("Trying to start process now"));
  if (!CanAllocate()) {
    if (IsEnabled() && IsEmpty() && sNumBlockers > 0) {
      // If it's too early to allocate a process let's retry later.
      AllocateAfterDelay();
    }
    return;
  }

  UniqueContentParentKeepAlive process = ContentParent::MakePreallocProcess();
  if (!process) {
    // We fully failed to create a prealloc process. Don't try to kick off a new
    // preallocation here, to avoid possible looping.
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
            ("Failed to launch prealloc process"));
    return;
  }

  process->WaitForLaunchAsync(PROCESS_PRIORITY_PREALLOC)
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [self = RefPtr{this},
           process = RefPtr{process.get()}](UniqueContentParentKeepAlive) {
            if (process->IsDead()) {
              self->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
              // RemoveFromList().  We won't try to kick off a new
              // preallocation here, to avoid possible looping if something is
              // causing them to consistently fail; if everything is ok on the
              // next allocation request we'll kick off creation.
            } else if (self->CanAllocate()) {
              // Continue prestarting processes if needed
              if (self->mPreallocatedProcesses.Length() <
                  self->mNumberPreallocs) {
                self->AllocateOnIdle();
              }
            }
          },
          [self = RefPtr{this}, process = RefPtr{process.get()}]() {
            self->Erase(process);
          });

  mPreallocatedProcesses.AppendElement(std::move(process));
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("Preallocated = %lu of %d processes",
           (unsigned long)mPreallocatedProcesses.Length(), mNumberPreallocs));
}

void PreallocatedProcessManagerImpl::Disable() {
  if (!mEnabled) {
    return;
  }

  mEnabled = false;
  CloseProcesses();
}

void PreallocatedProcessManagerImpl::CloseProcesses() {
  // Drop our KeepAlives on these processes. This will automatically lead to the
  // processes being shut down when no keepalives are left.
  mPreallocatedProcesses.Clear();
}

inline PreallocatedProcessManagerImpl*
PreallocatedProcessManager::GetPPMImpl() {
  if (PreallocatedProcessManagerImpl::IsShutdown()) {
    return nullptr;
  }
  return PreallocatedProcessManagerImpl::Singleton();
}

/* static */
bool PreallocatedProcessManager::Enabled() {
  if (auto impl = GetPPMImpl()) {
    return impl->IsEnabled();
  }
  return false;
}

/* static */
void PreallocatedProcessManager::AddBlocker(const nsACString& aRemoteType,
                                            ContentParent* aParent) {
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("AddBlocker: %s %p (sNumBlockers=%d)",
           PromiseFlatCString(aRemoteType).get(), aParent,
           PreallocatedProcessManagerImpl::sNumBlockers));
  if (auto impl = GetPPMImpl()) {
    impl->AddBlocker(aParent);
  }
}

/* static */
void PreallocatedProcessManager::RemoveBlocker(const nsACString& aRemoteType,
                                               ContentParent* aParent) {
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
          ("RemoveBlocker: %s %p (sNumBlockers=%d)",
           PromiseFlatCString(aRemoteType).get(), aParent,
           PreallocatedProcessManagerImpl::sNumBlockers));
  if (auto impl = GetPPMImpl()) {
    impl->RemoveBlocker(aParent);
  }
}

/* static */
UniqueContentParentKeepAlive PreallocatedProcessManager::Take(
    const nsACString& aRemoteType) {
  if (auto impl = GetPPMImpl()) {
    return impl->Take(aRemoteType);
  }
  return nullptr;
}

/* static */
void PreallocatedProcessManager::Erase(ContentParent* aParent) {
  if (auto impl = GetPPMImpl()) {
    impl->Erase(aParent);
  }
}

}  // namespace mozilla

Messung V0.5
C=91 H=98 G=94

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.