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

Quelle  SharedThreadPool.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/SharedThreadPool.h"
#include "mozilla/Monitor.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Services.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/StaticPtr.h"
#include "nsTHashMap.h"
#include "nsXPCOMCIDInternal.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIThreadManager.h"
#include "nsThreadPool.h"

namespace mozilla {

// Created and destroyed on the main thread.
static StaticAutoPtr<ReentrantMonitor> sMonitor;

// Hashtable, maps thread pool name to SharedThreadPool instance.
// Modified only on the main thread.
static StaticAutoPtr<nsTHashMap<nsCStringHashKey, SharedThreadPool*>> sPools;

static already_AddRefed<nsIThreadPool> CreateThreadPool(const nsCString& aName);

class SharedThreadPoolShutdownObserver : public nsIObserver {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIOBSERVER
 protected:
  virtual ~SharedThreadPoolShutdownObserver() = default;
};

NS_IMPL_ISUPPORTS(SharedThreadPoolShutdownObserver, nsIObserver, nsISupports)

NS_IMETHODIMP
SharedThreadPoolShutdownObserver::Observe(nsISupports* aSubject,
                                          const char* aTopic,
                                          const char16_t* aData) {
  MOZ_RELEASE_ASSERT(!strcmp(aTopic, "xpcom-shutdown-threads"));
#ifdef EARLY_BETA_OR_EARLIER
  {
    ReentrantMonitorAutoEnter mon(*sMonitor);
    if (!sPools->IsEmpty()) {
      nsAutoCString str;
      for (const auto& key : sPools->Keys()) {
        str.AppendPrintf("\"%s\" ", nsAutoCString(key).get());
      }
      printf_stderr(
          "SharedThreadPool in xpcom-shutdown-threads. Waiting for "
          "pools %s\n",
          str.get());
    }
  }
#endif
  SharedThreadPool::SpinUntilEmpty();
  sMonitor = nullptr;
  sPools = nullptr;
  return NS_OK;
}

void SharedThreadPool::InitStatics() {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!sMonitor && !sPools);
  sMonitor = new ReentrantMonitor("SharedThreadPool");
  sPools = new nsTHashMap<nsCStringHashKey, SharedThreadPool*>();
  nsCOMPtr<nsIObserverService> obsService =
      mozilla::services::GetObserverService();
  nsCOMPtr<nsIObserver> obs = new SharedThreadPoolShutdownObserver();
  obsService->AddObserver(obs, "xpcom-shutdown-threads"false);
}

/* static */
bool SharedThreadPool::IsEmpty() {
  ReentrantMonitorAutoEnter mon(*sMonitor);
  return !sPools->Count();
}

/* static */
void SharedThreadPool::SpinUntilEmpty() {
  MOZ_ASSERT(NS_IsMainThread());
  SpinEventLoopUntil("SharedThreadPool::SpinUntilEmpty"_ns, []() -> bool {
    sMonitor->AssertNotCurrentThreadIn();
    return IsEmpty();
  });
}

already_AddRefed<SharedThreadPool> SharedThreadPool::Get(
    const nsCString& aName, uint32_t aThreadLimit) {
  MOZ_ASSERT(sMonitor && sPools);
  ReentrantMonitorAutoEnter mon(*sMonitor);
  RefPtr<SharedThreadPool> pool;

  return sPools->WithEntryHandle(
      aName, [&](auto&& entry) -> already_AddRefed<SharedThreadPool> {
        if (entry) {
          pool = entry.Data();
          if (NS_FAILED(pool->EnsureThreadLimitIsAtLeast(aThreadLimit))) {
            NS_WARNING("Failed to set limits on thread pool");
          }
        } else {
          nsCOMPtr<nsIThreadPool> threadPool(CreateThreadPool(aName));
          if (NS_WARN_IF(!threadPool)) {
            sPools->Remove(aName);  // XXX entry.Remove()
            return nullptr;
          }
          pool = new SharedThreadPool(aName, threadPool);

          // Set the thread and idle limits. Note that we don't rely on the
          // EnsureThreadLimitIsAtLeast() call below, as the default thread
          // limit is 4, and if aThreadLimit is less than 4 we'll end up with a
          // pool with 4 threads rather than what we expected; so we'll have
          // unexpected behaviour.
          nsresult rv = pool->SetThreadLimit(aThreadLimit);
          if (NS_WARN_IF(NS_FAILED(rv))) {
            sPools->Remove(aName);  // XXX entry.Remove()
            return nullptr;
          }

          rv = pool->SetIdleThreadLimit(aThreadLimit);
          if (NS_WARN_IF(NS_FAILED(rv))) {
            sPools->Remove(aName);  // XXX entry.Remove()
            return nullptr;
          }

          entry.Insert(pool.get());
        }

        return pool.forget();
      });
}

NS_IMETHODIMP_(MozExternalRefCountType) SharedThreadPool::AddRef(void) {
  MOZ_ASSERT(sMonitor);
  ReentrantMonitorAutoEnter mon(*sMonitor);
  MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
  nsrefcnt count = ++mRefCnt;
  NS_LOG_ADDREF(this, count, "SharedThreadPool"sizeof(*this));
  return count;
}

NS_IMETHODIMP_(MozExternalRefCountType) SharedThreadPool::Release(void) {
  MOZ_ASSERT(sMonitor);
  ReentrantMonitorAutoEnter mon(*sMonitor);
  nsrefcnt count = --mRefCnt;
  NS_LOG_RELEASE(this, count, "SharedThreadPool");
  if (count) {
    return count;
  }

  // Remove SharedThreadPool from table of pools.
  sPools->Remove(mName);
  MOZ_ASSERT(!sPools->Get(mName));

  // Dispatch an event to the main thread to call Shutdown() on
  // the nsIThreadPool. The Runnable here will add a refcount to the pool,
  // and when the Runnable releases the nsIThreadPool it will be deleted.
  NS_DispatchToMainThread(NewRunnableMethod("nsIThreadPool::Shutdown", mPool,
                                            &nsIThreadPool::Shutdown));

  // Stabilize refcount, so that if something in the dtor QIs, it won't explode.
  mRefCnt = 1;
  delete this;
  return 0;
}

NS_IMPL_QUERY_INTERFACE(SharedThreadPool, nsIThreadPool, nsIEventTarget)

SharedThreadPool::SharedThreadPool(const nsCString& aName, nsIThreadPool* aPool)
    : mName(aName), mPool(aPool), mRefCnt(0) {}

SharedThreadPool::~SharedThreadPool() = default;

nsresult SharedThreadPool::EnsureThreadLimitIsAtLeast(uint32_t aLimit) {
  // We limit the number of threads that we use. Note that we
  // set the thread limit to the same as the idle limit so that we're not
  // constantly creating and destroying threads (see Bug 881954). When the
  // thread pool threads shutdown they dispatch an event to the main thread
  // to call nsIThread::Shutdown(), and if we're very busy that can take a
  // while to run, and we end up with dozens of extra threads. Note that
  // threads that are idle for 60 seconds are shutdown naturally.
  uint32_t existingLimit = 0;
  nsresult rv;

  rv = mPool->GetThreadLimit(&existingLimit);
  NS_ENSURE_SUCCESS(rv, rv);
  if (aLimit > existingLimit) {
    rv = mPool->SetThreadLimit(aLimit);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  rv = mPool->GetIdleThreadLimit(&existingLimit);
  NS_ENSURE_SUCCESS(rv, rv);
  if (aLimit > existingLimit) {
    rv = mPool->SetIdleThreadLimit(aLimit);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  return NS_OK;
}

static already_AddRefed<nsIThreadPool> CreateThreadPool(
    const nsCString& aName) {
  nsCOMPtr<nsIThreadPool> pool = new nsThreadPool();

  nsresult rv = pool->SetName(aName);
  NS_ENSURE_SUCCESS(rv, nullptr);

  rv = pool->SetThreadStackSize(nsIThreadManager::kThreadPoolStackSize);
  NS_ENSURE_SUCCESS(rv, nullptr);

  return pool.forget();
}

}  // namespace mozilla

100%


¤ Dauer der Verarbeitung: 0.2 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 ist noch experimentell.