Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/xpcom/tests/gtest/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 5 kB image not shown  

Quelle  TestAutoRefCnt.cpp

  Sprache: C
 

/* 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 "nsISupportsImpl.h"

#include "mozilla/Atomics.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"

#include "gtest/gtest.h"
#include "mozilla/gtest/MozAssertions.h"

using namespace mozilla;

class nsThreadSafeAutoRefCntRunner final : public Runnable {
 public:
  NS_IMETHOD Run() final {
    for (int i = 0; i < 10000; i++) {
      if (++sRefCnt == 1) {
        sIncToOne++;
      }
      if (--sRefCnt == 0) {
        sDecToZero++;
      }
    }
    return NS_OK;
  }

  static ThreadSafeAutoRefCnt sRefCnt;
  static Atomic<uint32_t, Relaxed> sIncToOne;
  static Atomic<uint32_t, Relaxed> sDecToZero;

  nsThreadSafeAutoRefCntRunner() : Runnable("nsThreadSafeAutoRefCntRunner") {}

 private:
  ~nsThreadSafeAutoRefCntRunner() = default;
};

ThreadSafeAutoRefCnt nsThreadSafeAutoRefCntRunner::sRefCnt;
Atomic<uint32_t, Relaxed> nsThreadSafeAutoRefCntRunner::sIncToOne(0);
Atomic<uint32_t, Relaxed> nsThreadSafeAutoRefCntRunner::sDecToZero(0);

class nsThreadSafeAutoRefCntDecrementWithLimitRunner final : public Runnable {
 public:
  static constexpr size_t kDecrementsPerThread = 1000;

  NS_IMETHOD Run() final {
    for (size_t i = 0; i < kDecrementsPerThread; i++) {
      auto [ok, count] = sRefCnt.DecrementWithLimit<1>();
      if (!ok) {
        sLimitHits++;
        break;
      }
    }
    return NS_OK;
  }

  static ThreadSafeAutoRefCnt sRefCnt;
  // Relaxed ordering so sLimitHits doesn't affect the ordering properties of
  // DecrementWithLimit being tested.
  static Atomic<uint32_t, Relaxed> sLimitHits;

  nsThreadSafeAutoRefCntDecrementWithLimitRunner()
      : Runnable("nsThreadSafeAutoRefCntDecrementWithLimitRunner") {}

 private:
  ~nsThreadSafeAutoRefCntDecrementWithLimitRunner() = default;
};

ThreadSafeAutoRefCnt nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt;
Atomic<uint32_t, Relaxed>
    nsThreadSafeAutoRefCntDecrementWithLimitRunner::sLimitHits(0);

// When a refcounted object is actually owned by a cache, we may not
// want to release the object after last reference gets released. In
// this pattern, the cache may rely on the balance of increment to one
// and decrement to zero, so that it can maintain a counter for GC.
TEST(AutoRefCnt, ThreadSafeAutoRefCntBalance)
{
  static const size_t kThreadCount = 4;
  nsCOMPtr<nsIThread> threads[kThreadCount];
  for (auto& thread : threads) {
    nsresult rv = NS_NewNamedThread("AutoRefCnt Test", getter_AddRefs(thread),
                                    new nsThreadSafeAutoRefCntRunner);
    EXPECT_NS_SUCCEEDED(rv);
  }
  for (const auto& thread : threads) {
    thread->Shutdown();
  }
  EXPECT_EQ(nsThreadSafeAutoRefCntRunner::sRefCnt, nsrefcnt(0));
  EXPECT_EQ(nsThreadSafeAutoRefCntRunner::sIncToOne,
            nsThreadSafeAutoRefCntRunner::sDecToZero);
}

// Spawns kThreadCount threads each attempting kDecrementsPerThread
// decrements, then verifies the final refcount is 1 and that exactly
// aExpectedLimitHits threads hit the limit.
// kInitial is derived from aExpectedLimitHits so that exactly
// (kThreadCount - aExpectedLimitHits) threads can complete all their
// decrements; the rest hit the limit.
static void RunDecrementWithLimitThreaded(uint32_t aExpectedLimitHits) {
  static const size_t kThreadCount = 4;
  const nsrefcnt kInitial =
      (kThreadCount - aExpectedLimitHits) *
          nsThreadSafeAutoRefCntDecrementWithLimitRunner::kDecrementsPerThread +
      1;
  nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt = kInitial;
  nsThreadSafeAutoRefCntDecrementWithLimitRunner::sLimitHits = 0;

  nsCOMPtr<nsIThread> threads[kThreadCount];
  for (auto& thread : threads) {
    nsresult rv =
        NS_NewNamedThread("AutoRefCnt Test", getter_AddRefs(thread),
                          new nsThreadSafeAutoRefCntDecrementWithLimitRunner);
    EXPECT_NS_SUCCEEDED(rv);
  }
  for (const auto& thread : threads) {
    thread->Shutdown();
  }
  EXPECT_EQ(nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt,
            nsrefcnt(1));
  EXPECT_EQ(nsThreadSafeAutoRefCntDecrementWithLimitRunner::sLimitHits,
            uint32_t(aExpectedLimitHits));
}

// Verify DecrementWithLimit with no lost updates when the limit is never hit.
TEST(AutoRefCnt, ThreadSafeAutoRefCntDecrementWithLimitNoHit)
{
  RunDecrementWithLimitThreaded(0);
}

// Verify DecrementWithLimit correctly enforces the limit. With kInitial == 1
// (equal to Limit), all threads hit the limit on their first attempt,
// giving a deterministic sLimitHits == kThreadCount.
TEST(AutoRefCnt, ThreadSafeAutoRefCntDecrementWithLimitHit)
{
  static const size_t kThreadCount = 4;
  RunDecrementWithLimitThreaded(kThreadCount);
}

// Verify DecrementWithLimit performs exactly kDecrementsPerThread successful
// decrements before hitting the limit. Single-threaded for determinism.
TEST(AutoRefCnt, ThreadSafeAutoRefCntDecrementWithLimitSequential)
{
  const nsrefcnt kDecrementsPerThread =
      nsThreadSafeAutoRefCntDecrementWithLimitRunner::kDecrementsPerThread;
  // Initialize so exactly kDecrementsPerThread decrements succeed before
  // hitting the limit at 1.
  nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt =
      kDecrementsPerThread + 1;

  size_t successes = 0;
  while (true) {
    auto [ok, count] = nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt
                           .DecrementWithLimit<1>();
    if (!ok) {
      break;
    }
    successes++;
  }

  EXPECT_EQ(successes, size_t(kDecrementsPerThread));
  EXPECT_EQ(nsThreadSafeAutoRefCntDecrementWithLimitRunner::sRefCnt,
            nsrefcnt(1));
}

Messung V0.5 in Prozent
C=84 H=92 G=87

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.