Revert "ipcz: Ref counted fragments"
This reverts commit 6385cfb931f738334dc59e9d7d39eb7daa70f7ba.
Reason for revert: The introduced tests are consistently failing on 2 Linux builders. First failure on each:
https://ci.chromium.org/ui/p/chromium/builders/ci/Linux%20Tests%20(dbg)(1)/106281/overview
https://ci.chromium.org/ui/p/chromium/builders/ci/linux-chromeos-dbg/29400/overview
Original change's description:
> ipcz: Ref counted fragments
>
> Introduces RefCountedFragment and FragmentRef<T> as helpers to support
> ref-counted objects living in shared memory fragments, as allocated
> via NodeLinkMemory.
>
> Also introduces some builtin BlockAllocators to each NodeLinkMemory's
> primary buffer.
>
> This change lays the ground work for dynamic allocation of managed state
> objects between each connected pair of Routers.
>
> Bug: 1299283
> Change-Id: Ibc2859a8cdcca00fd0d9602664eceaaccb5bd9ae
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3750056
> Reviewed-by: Alex Gough <ajgo@chromium.org>
> Commit-Queue: Ken Rockot <rockot@google.com>
> Cr-Commit-Position: refs/heads/main@{#1021940}
Bug: 1299283
Change-Id: Ib4ac409e26d358366f735b224b233729f4ea257a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3750295
Commit-Queue: Guillaume Jenkins <gujen@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Owners-Override: Guillaume Jenkins <gujen@google.com>
Cr-Commit-Position: refs/heads/main@{#1022125}
NOKEYCHECK=True
GitOrigin-RevId: 02f9e51c84006f83a5dc6f5d47ed038b97274f5e
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 85a4b98..75aef4a 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -218,7 +218,6 @@
"ipcz/driver_transport.h",
"ipcz/fragment.h",
"ipcz/fragment_descriptor.h",
- "ipcz/fragment_ref.h",
"ipcz/link_side.h",
"ipcz/link_type.h",
"ipcz/message.h",
@@ -230,7 +229,6 @@
"ipcz/parcel.h",
"ipcz/parcel_queue.h",
"ipcz/portal.h",
- "ipcz/ref_counted_fragment.h",
"ipcz/remote_router_link.h",
"ipcz/router.h",
"ipcz/sequence_number.h",
@@ -252,7 +250,6 @@
"ipcz/driver_transport.cc",
"ipcz/fragment.cc",
"ipcz/fragment_descriptor.cc",
- "ipcz/fragment_ref.cc",
"ipcz/handle_type.h",
"ipcz/link_side.cc",
"ipcz/link_type.cc",
@@ -278,7 +275,6 @@
"ipcz/parcel.cc",
"ipcz/parcel_queue.cc",
"ipcz/portal.cc",
- "ipcz/ref_counted_fragment.cc",
"ipcz/remote_router_link.cc",
"ipcz/router.cc",
"ipcz/router_descriptor.cc",
@@ -334,7 +330,6 @@
"ipcz/node_connector_test.cc",
"ipcz/node_link_test.cc",
"ipcz/parcel_queue_test.cc",
- "ipcz/ref_counted_fragment_test.cc",
"ipcz/sequenced_queue_test.cc",
"reference_drivers/sync_reference_driver_test.cc",
"remote_portal_test.cc",
diff --git a/src/ipcz/fragment_ref.cc b/src/ipcz/fragment_ref.cc
deleted file mode 100644
index e586924..0000000
--- a/src/ipcz/fragment_ref.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipcz/fragment_ref.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "ipcz/fragment.h"
-#include "ipcz/node_link_memory.h"
-#include "ipcz/ref_counted_fragment.h"
-#include "util/ref_counted.h"
-
-namespace ipcz::internal {
-
-GenericFragmentRef::GenericFragmentRef() = default;
-
-GenericFragmentRef::GenericFragmentRef(Ref<NodeLinkMemory> memory,
- const Fragment& fragment)
- : memory_(std::move(memory)), fragment_(fragment) {}
-
-GenericFragmentRef::~GenericFragmentRef() {
- reset();
-}
-
-void GenericFragmentRef::reset() {
- Ref<NodeLinkMemory> memory = std::move(memory_);
- if (fragment_.is_null()) {
- return;
- }
-
- Fragment fragment;
- std::swap(fragment, fragment_);
- if (!fragment.is_addressable()) {
- return;
- }
-
- auto* ref_counted = static_cast<RefCountedFragment*>(fragment.address());
- if (ref_counted->ReleaseRef() > 1 || !memory) {
- return;
- }
-
- memory->buffer_pool().FreeFragment(fragment);
-}
-
-Fragment GenericFragmentRef::release() {
- Fragment fragment;
- std::swap(fragment_, fragment);
- memory_.reset();
- return fragment;
-}
-
-} // namespace ipcz::internal
diff --git a/src/ipcz/fragment_ref.h b/src/ipcz/fragment_ref.h
deleted file mode 100644
index e54135b..0000000
--- a/src/ipcz/fragment_ref.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPCZ_SRC_IPCZ_FRAGMENT_REF_H_
-#define IPCZ_SRC_IPCZ_FRAGMENT_REF_H_
-
-#include <algorithm>
-#include <type_traits>
-#include <utility>
-
-#include "ipcz/fragment.h"
-#include "ipcz/fragment_descriptor.h"
-#include "ipcz/ref_counted_fragment.h"
-#include "third_party/abseil-cpp/absl/base/macros.h"
-#include "util/ref_counted.h"
-
-namespace ipcz {
-
-class NodeLinkMemory;
-
-namespace internal {
-
-// Base class for any FragmentRef<T>, implementing common behavior for managing
-// the underlying RefCountedFragment.
-class GenericFragmentRef {
- public:
- GenericFragmentRef();
-
- // Does not increase the ref count of the underlying RefCountedFragment,
- // effectively assuming ownership of a previously acquired ref.
- GenericFragmentRef(Ref<NodeLinkMemory> memory, const Fragment& fragment);
-
- ~GenericFragmentRef();
-
- const Ref<NodeLinkMemory>& memory() const { return memory_; }
- const Fragment& fragment() const { return fragment_; }
-
- bool is_null() const { return fragment_.is_null(); }
- bool is_addressable() const { return fragment_.is_addressable(); }
- bool is_pending() const { return fragment_.is_pending(); }
-
- void reset();
- Fragment release();
-
- int32_t ref_count_for_testing() const {
- return AsRefCountedFragment()->ref_count_for_testing();
- }
-
- protected:
- RefCountedFragment* AsRefCountedFragment() const {
- return static_cast<RefCountedFragment*>(fragment_.address());
- }
-
- // The NodeLinkMemory who ultimately owns this fragment's memory. May be null
- // if the FragmentRef is unmanaged.
- Ref<NodeLinkMemory> memory_;
-
- Fragment fragment_;
-};
-
-} // namespace internal
-
-// Holds a reference to a RefCountedFragment. When this object is destroyed, the
-// underlying ref count is decreased. If the ref count is decreased to zero, the
-// underlying Fragment is returned to its NodeLinkMemory.
-//
-// Some FragmentRefs may be designated as "unmanaged", meaning that they will
-// never attempt to free the underlying Fragment. These refs are used to
-// preserve type compatibility with other similar (but managed) FragmentRefs
-// when the underlying Fragment isn't dynamically allocated and can't be freed.
-//
-// For example most RouterLinkState fragments are dynamically allocated and
-// managed by FragmentRefs, but some instances are allocated at fixed locations
-// within the NodeLinkMemory and cannot be freed or reused. In both cases, ipcz
-// can refer to these objects using a FragmentRef<RouterLinkState>.
-template <typename T>
-class FragmentRef : public internal::GenericFragmentRef {
- public:
- static_assert(std::is_base_of<RefCountedFragment, T>::value,
- "T must inherit RefCountedFragment for FragmentRef<T>");
-
- constexpr FragmentRef() = default;
- constexpr FragmentRef(std::nullptr_t) : FragmentRef() {}
-
- // Adopts an existing ref to the RefCountedFragment located at the beginning
- // of `fragment`, which is a Fragment owned by `memory.
- FragmentRef(decltype(RefCountedFragment::kAdoptExistingRef),
- Ref<NodeLinkMemory> memory,
- const Fragment& fragment)
- : GenericFragmentRef(std::move(memory), fragment) {
- ABSL_ASSERT(memory_);
- ABSL_ASSERT(fragment_.is_null() || fragment_.size() >= sizeof(T));
- }
-
- // Constructs an unmanaged FragmentRef, which references `fragment` and
- // updates its refcount, but which never attempts to release `fragment` back
- // to its NodeLinkMemory. This is only safe to use with Fragments which cannot
- // be freed.
- FragmentRef(decltype(RefCountedFragment::kUnmanagedRef),
- const Fragment& fragment)
- : GenericFragmentRef(nullptr, fragment) {
- ABSL_ASSERT(fragment_.is_null() || fragment_.size() >= sizeof(T));
- }
-
- FragmentRef(const FragmentRef<T>& other)
- : GenericFragmentRef(other.memory(), other.fragment()) {
- if (!fragment_.is_null()) {
- ABSL_ASSERT(fragment_.is_addressable());
- AsRefCountedFragment()->AddRef();
- }
- }
-
- FragmentRef(FragmentRef<T>&& other) noexcept
- : GenericFragmentRef(std::move(other.memory_), other.fragment_) {
- other.release();
- }
-
- FragmentRef<T>& operator=(const FragmentRef<T>& other) {
- reset();
- memory_ = other.memory();
- fragment_ = other.fragment();
- if (!fragment_.is_null()) {
- ABSL_ASSERT(fragment_.is_addressable());
- AsRefCountedFragment()->AddRef();
- }
- return *this;
- }
-
- FragmentRef<T>& operator=(FragmentRef<T>&& other) {
- reset();
- memory_ = std::move(other.memory_);
- fragment_ = other.release();
- return *this;
- }
-
- T* get() const { return static_cast<T*>(fragment_.address()); }
- T* operator->() const { return get(); }
- T& operator*() const { return *get(); }
-};
-
-} // namespace ipcz
-
-#endif // IPCZ_SRC_IPCZ_FRAGMENT_REF_H_
diff --git a/src/ipcz/node_link_memory.cc b/src/ipcz/node_link_memory.cc
index 012f26c..5a8aba0 100644
--- a/src/ipcz/node_link_memory.cc
+++ b/src/ipcz/node_link_memory.cc
@@ -25,11 +25,12 @@
// Fixed allocation size for each NodeLink's primary shared buffer.
constexpr size_t kPrimaryBufferSize = 65536;
-// The front of the primary buffer is reserved for special current and future
-// uses which require synchronous availability throughout a link's lifetime.
-constexpr size_t kPrimaryBufferReservedHeaderSize = 256;
+} // namespace
-struct IPCZ_ALIGN(8) PrimaryBufferHeader {
+// This structure always sits at offset 0 in the primary buffer and has a fixed
+// layout according to the NodeLink's agreed upon protocol version. This is the
+// layout for version 0 (currently the only version.)
+struct IPCZ_ALIGN(8) NodeLinkMemory::PrimaryBuffer {
// Atomic generator for new unique BufferIds to use across the associated
// NodeLink. This allows each side of a NodeLink to generate new BufferIds
// spontaneously without synchronization or risk of collisions.
@@ -41,51 +42,6 @@
std::atomic<uint64_t> next_sublink_id;
};
-static_assert(sizeof(PrimaryBufferHeader) < kPrimaryBufferReservedHeaderSize);
-
-constexpr size_t kPrimaryBufferHeaderPaddingSize =
- kPrimaryBufferReservedHeaderSize - sizeof(PrimaryBufferHeader);
-
-} // namespace
-
-// This structure always sits at offset 0 in the primary buffer and has a fixed
-// layout according to the NodeLink's agreed upon protocol version. This is the
-// layout for version 0 (currently the only version.)
-struct IPCZ_ALIGN(8) NodeLinkMemory::PrimaryBuffer {
- // Header + padding occupies the first 256 bytes.
- PrimaryBufferHeader header;
- uint8_t reserved_header_padding[kPrimaryBufferHeaderPaddingSize];
-
- // Reserved memory for a series of fixed block allocators. Additional
- // allocators may be adopted by a NodeLinkMemory over its lifetime, but these
- // ones remain fixed within the primary buffer.
- std::array<uint8_t, 4096> mem_for_64_byte_blocks;
- std::array<uint8_t, 12288> mem_for_256_byte_blocks;
- std::array<uint8_t, 15360> mem_for_512_byte_blocks;
- std::array<uint8_t, 11264> mem_for_1024_byte_blocks;
- std::array<uint8_t, 16384> mem_for_2048_byte_blocks;
-
- BlockAllocator block_allocator_64() {
- return BlockAllocator(absl::MakeSpan(mem_for_64_byte_blocks), 64);
- }
-
- BlockAllocator block_allocator_256() {
- return BlockAllocator(absl::MakeSpan(mem_for_256_byte_blocks), 256);
- }
-
- BlockAllocator block_allocator_512() {
- return BlockAllocator(absl::MakeSpan(mem_for_512_byte_blocks), 512);
- }
-
- BlockAllocator block_allocator_1024() {
- return BlockAllocator(absl::MakeSpan(mem_for_1024_byte_blocks), 1024);
- }
-
- BlockAllocator block_allocator_2048() {
- return BlockAllocator(absl::MakeSpan(mem_for_2048_byte_blocks), 2048);
- }
-};
-
NodeLinkMemory::NodeLinkMemory(Ref<Node> node,
DriverMemoryMapping primary_buffer_memory)
: node_(std::move(node)),
@@ -96,17 +52,8 @@
static_assert(sizeof(PrimaryBuffer) <= kPrimaryBufferSize,
"PrimaryBuffer structure is too large.");
- buffer_pool_.AddBuffer(kPrimaryBufferId, std::move(primary_buffer_memory));
- buffer_pool_.RegisterBlockAllocator(kPrimaryBufferId,
- primary_buffer_.block_allocator_64());
- buffer_pool_.RegisterBlockAllocator(kPrimaryBufferId,
- primary_buffer_.block_allocator_256());
- buffer_pool_.RegisterBlockAllocator(kPrimaryBufferId,
- primary_buffer_.block_allocator_512());
- buffer_pool_.RegisterBlockAllocator(kPrimaryBufferId,
- primary_buffer_.block_allocator_1024());
- buffer_pool_.RegisterBlockAllocator(kPrimaryBufferId,
- primary_buffer_.block_allocator_2048());
+ buffer_pool_.AddBuffer(BufferId{kPrimaryBufferId},
+ std::move(primary_buffer_memory));
}
NodeLinkMemory::~NodeLinkMemory() = default;
@@ -124,21 +71,15 @@
PrimaryBuffer& primary_buffer = memory->primary_buffer_;
// The first allocable BufferId is 1, because the primary buffer uses 0.
- primary_buffer.header.next_buffer_id.store(1, std::memory_order_relaxed);
+ primary_buffer.next_buffer_id.store(1, std::memory_order_relaxed);
// The first allocable SublinkId is kMaxInitialPortals. This way it doesn't
// matter whether the two ends of a NodeLink initiate their connection with a
// different initial portal count: neither can request more than
// kMaxInitialPortals, so neither will be assuming initial ownership of any
// SublinkIds at or above this value.
- primary_buffer.header.next_sublink_id.store(kMaxInitialPortals,
- std::memory_order_release);
-
- primary_buffer.block_allocator_64().InitializeRegion();
- primary_buffer.block_allocator_256().InitializeRegion();
- primary_buffer.block_allocator_512().InitializeRegion();
- primary_buffer.block_allocator_1024().InitializeRegion();
- primary_buffer.block_allocator_2048().InitializeRegion();
+ primary_buffer.next_sublink_id.store(kMaxInitialPortals,
+ std::memory_order_release);
return {
.node_link_memory = std::move(memory),
@@ -154,12 +95,12 @@
}
BufferId NodeLinkMemory::AllocateNewBufferId() {
- return BufferId{primary_buffer_.header.next_buffer_id.fetch_add(
- 1, std::memory_order_relaxed)};
+ return BufferId{
+ primary_buffer_.next_buffer_id.fetch_add(1, std::memory_order_relaxed)};
}
SublinkId NodeLinkMemory::AllocateSublinkIds(size_t count) {
- return SublinkId{primary_buffer_.header.next_sublink_id.fetch_add(
+ return SublinkId{primary_buffer_.next_sublink_id.fetch_add(
count, std::memory_order_relaxed)};
}
diff --git a/src/ipcz/node_link_memory.h b/src/ipcz/node_link_memory.h
index 014a78e..b4d65a6 100644
--- a/src/ipcz/node_link_memory.h
+++ b/src/ipcz/node_link_memory.h
@@ -63,7 +63,7 @@
// Exposes the underlying BufferPool which owns all shared buffers for this
// NodeLinkMemory and which facilitates dynamic allocation of the fragments
// within.
- BufferPool& buffer_pool() { return buffer_pool_; }
+ BufferPool& buffer_pool();
// Returns a new BufferId which should still be unused by any buffer in this
// NodeLinkMemory's BufferPool, or that of its peer NodeLinkMemory. When
diff --git a/src/ipcz/ref_counted_fragment.cc b/src/ipcz/ref_counted_fragment.cc
deleted file mode 100644
index 14b21cf..0000000
--- a/src/ipcz/ref_counted_fragment.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipcz/ref_counted_fragment.h"
-
-#include "third_party/abseil-cpp/absl/base/macros.h"
-
-namespace ipcz {
-
-RefCountedFragment::RefCountedFragment() = default;
-
-RefCountedFragment::~RefCountedFragment() = default;
-
-void RefCountedFragment::AddRef() {
- ref_count_.fetch_add(1, std::memory_order_relaxed);
-}
-
-int32_t RefCountedFragment::ReleaseRef() {
- return ref_count_.fetch_sub(1, std::memory_order_acq_rel);
-}
-
-} // namespace ipcz
diff --git a/src/ipcz/ref_counted_fragment.h b/src/ipcz/ref_counted_fragment.h
deleted file mode 100644
index ff69c45..0000000
--- a/src/ipcz/ref_counted_fragment.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPCZ_SRC_IPCZ_REF_COUNTED_FRAGMENT_H_
-#define IPCZ_SRC_IPCZ_REF_COUNTED_FRAGMENT_H_
-
-#include <atomic>
-
-#include "ipcz/ipcz.h"
-#include "util/ref_counted.h"
-
-namespace ipcz {
-
-// A RefCountedFragment is an object allocated within a shared Fragment from
-// NodeLinkMemory, and which is automatially freed when its last reference is
-// released. Consumers can hold onto references to RefCountedFragment objects
-// by holding a FragmentRef.
-struct IPCZ_ALIGN(4) RefCountedFragment {
- enum { kAdoptExistingRef };
- enum { kUnmanagedRef };
-
- RefCountedFragment();
- ~RefCountedFragment();
-
- int32_t ref_count_for_testing() const { return ref_count_; }
-
- // Increments the reference count for this object.
- void AddRef();
-
- // Releases a reference and returns the previous reference count. If this
- // returns 1, the underlying Fragment can be safely freed.
- int32_t ReleaseRef();
-
- private:
- std::atomic<int32_t> ref_count_{1};
-};
-
-} // namespace ipcz
-
-#endif // IPCZ_SRC_IPCZ_REF_COUNTED_FRAGMENT_H_
diff --git a/src/ipcz/ref_counted_fragment_test.cc b/src/ipcz/ref_counted_fragment_test.cc
deleted file mode 100644
index 5bb0db4..0000000
--- a/src/ipcz/ref_counted_fragment_test.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipcz/ref_counted_fragment.h"
-
-#include <atomic>
-#include <tuple>
-
-#include "ipcz/fragment.h"
-#include "ipcz/fragment_ref.h"
-#include "ipcz/node.h"
-#include "ipcz/node_link_memory.h"
-#include "reference_drivers/sync_reference_driver.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "util/ref_counted.h"
-
-namespace ipcz {
-namespace {
-
-const IpczDriver& kTestDriver = reference_drivers::kSyncReferenceDriver;
-
-using RefCountedFragmentTest = testing::Test;
-
-using TestObject = RefCountedFragment;
-
-TEST_F(RefCountedFragmentTest, NullRef) {
- FragmentRef<TestObject> ref;
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
-
- ref.reset();
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
-
- FragmentRef<TestObject> other1 = ref;
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
- EXPECT_TRUE(other1.is_null());
- EXPECT_FALSE(other1.is_addressable());
-
- FragmentRef<TestObject> other2 = std::move(ref);
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
- EXPECT_TRUE(other2.is_null());
- EXPECT_FALSE(other2.is_addressable());
-
- ref = other1;
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
- EXPECT_TRUE(other1.is_null());
- EXPECT_FALSE(other1.is_addressable());
-
- ref = std::move(other2);
- EXPECT_TRUE(ref.is_null());
- EXPECT_FALSE(ref.is_addressable());
- EXPECT_TRUE(other1.is_null());
- EXPECT_FALSE(other1.is_addressable());
-}
-
-TEST_F(RefCountedFragmentTest, SimpleRef) {
- TestObject object;
-
- FragmentRef<TestObject> ref(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object));
- EXPECT_EQ(1, object.ref_count_for_testing());
- ref.reset();
- EXPECT_EQ(0, object.ref_count_for_testing());
-}
-
-TEST_F(RefCountedFragmentTest, Copy) {
- TestObject object1;
-
- FragmentRef<TestObject> ref1(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object1));
- EXPECT_EQ(1, object1.ref_count_for_testing());
-
- FragmentRef<TestObject> other1 = ref1;
- EXPECT_EQ(2, object1.ref_count_for_testing());
- other1.reset();
- EXPECT_EQ(1, object1.ref_count_for_testing());
- EXPECT_TRUE(other1.is_null());
- EXPECT_FALSE(other1.is_addressable());
-
- TestObject object2;
- auto ref2 = FragmentRef<TestObject>(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object2));
- EXPECT_EQ(1, object1.ref_count_for_testing());
- EXPECT_EQ(1, object2.ref_count_for_testing());
- ref2 = ref1;
- EXPECT_EQ(2, object1.ref_count_for_testing());
- EXPECT_EQ(0, object2.ref_count_for_testing());
- EXPECT_FALSE(ref1.is_null());
- EXPECT_TRUE(ref1.is_addressable());
- EXPECT_FALSE(ref2.is_null());
- EXPECT_TRUE(ref2.is_addressable());
- ref1.reset();
- EXPECT_EQ(1, object1.ref_count_for_testing());
- EXPECT_EQ(0, object2.ref_count_for_testing());
- EXPECT_TRUE(ref1.is_null());
- EXPECT_FALSE(ref1.is_addressable());
- ref2.reset();
- EXPECT_EQ(0, object1.ref_count_for_testing());
- EXPECT_EQ(0, object2.ref_count_for_testing());
- EXPECT_TRUE(ref2.is_null());
- EXPECT_FALSE(ref2.is_addressable());
-}
-
-TEST_F(RefCountedFragmentTest, Move) {
- TestObject object1;
-
- FragmentRef<TestObject> ref1(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object1));
- EXPECT_EQ(1, ref1.ref_count_for_testing());
-
- FragmentRef<TestObject> other1 = std::move(ref1);
- EXPECT_EQ(1, object1.ref_count_for_testing());
- EXPECT_FALSE(other1.is_null());
- EXPECT_TRUE(other1.is_addressable());
- EXPECT_TRUE(ref1.is_null());
- EXPECT_FALSE(ref1.is_addressable());
- other1.reset();
- EXPECT_TRUE(other1.is_null());
- EXPECT_FALSE(other1.is_addressable());
- EXPECT_EQ(0, object1.ref_count_for_testing());
-
- TestObject object2;
- TestObject object3;
- FragmentRef<TestObject> ref2(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object2));
- FragmentRef<TestObject> ref3(
- RefCountedFragment::kUnmanagedRef,
- Fragment(FragmentDescriptor(BufferId(0), 0, 0), &object3));
-
- EXPECT_FALSE(ref2.is_null());
- EXPECT_TRUE(ref2.is_addressable());
- EXPECT_FALSE(ref3.is_null());
- EXPECT_TRUE(ref3.is_addressable());
- EXPECT_EQ(1, object2.ref_count_for_testing());
- EXPECT_EQ(1, object3.ref_count_for_testing());
- ref3 = std::move(ref2);
- EXPECT_EQ(1, object2.ref_count_for_testing());
- EXPECT_EQ(0, object3.ref_count_for_testing());
- EXPECT_TRUE(ref2.is_null());
- EXPECT_FALSE(ref2.is_addressable());
- EXPECT_FALSE(ref3.is_null());
- EXPECT_TRUE(ref3.is_addressable());
- ref3.reset();
- EXPECT_TRUE(ref3.is_null());
- EXPECT_FALSE(ref3.is_addressable());
- EXPECT_EQ(0, object2.ref_count_for_testing());
- EXPECT_EQ(0, object3.ref_count_for_testing());
-}
-
-TEST_F(RefCountedFragmentTest, Free) {
- auto node = MakeRefCounted<Node>(Node::Type::kNormal, kTestDriver,
- IPCZ_INVALID_DRIVER_HANDLE);
- auto memory = NodeLinkMemory::Allocate(std::move(node)).node_link_memory;
-
- // Allocate a ton of fragments and let them be released by FragmentRef on
- // destruction. If the fragments aren't freed properly, allocations will fail
- // and so will the test.
- constexpr size_t kNumAllocations = 100000;
- for (size_t i = 0; i < kNumAllocations; ++i) {
- Fragment fragment =
- memory->buffer_pool().AllocateFragment(sizeof(TestObject));
- EXPECT_TRUE(fragment.is_addressable());
- FragmentRef<TestObject> ref(RefCountedFragment::kAdoptExistingRef, memory,
- fragment);
- }
-}
-
-} // namespace
-} // namespace ipcz