-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
partition_alloc: copy ref_counted and scoped_refptr to PA library.
PS1 = just copying ref_counted and scoped_refptr to PA library Bug: 1151236 Change-Id: I0d35f6474f7f95bbf0766ba56d83aeae5b3afe1e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3637437 Reviewed-by: Anton Bikineev <bikineev@chromium.org> Reviewed-by: Yuki Shiino <yukishiino@chromium.org> Reviewed-by: Bartek Nowierski <bartekn@chromium.org> Commit-Queue: Takashi Sakamoto <tasak@google.com> Cr-Commit-Position: refs/heads/main@{#1002492}
- Loading branch information
Showing
8 changed files
with
681 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
base/allocator/partition_allocator/partition_alloc_base/atomic_ref_count.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) 2011 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. | ||
|
||
// This is a low level implementation of atomic semantics for reference | ||
// counting. Please use base/memory/ref_counted.h directly instead. | ||
|
||
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_ATOMIC_REF_COUNT_H_ | ||
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_ATOMIC_REF_COUNT_H_ | ||
|
||
#include <atomic> | ||
|
||
namespace partition_alloc::internal::base { | ||
|
||
class AtomicRefCount { | ||
public: | ||
constexpr AtomicRefCount() : ref_count_(0) {} | ||
explicit constexpr AtomicRefCount(int initial_value) | ||
: ref_count_(initial_value) {} | ||
|
||
// Increment a reference count. | ||
// Returns the previous value of the count. | ||
int Increment() { return Increment(1); } | ||
|
||
// Increment a reference count by "increment", which must exceed 0. | ||
// Returns the previous value of the count. | ||
int Increment(int increment) { | ||
return ref_count_.fetch_add(increment, std::memory_order_relaxed); | ||
} | ||
|
||
// Decrement a reference count, and return whether the result is non-zero. | ||
// Insert barriers to ensure that state written before the reference count | ||
// became zero will be visible to a thread that has just made the count zero. | ||
bool Decrement() { | ||
// TODO(jbroman): Technically this doesn't need to be an acquire operation | ||
// unless the result is 1 (i.e., the ref count did indeed reach zero). | ||
// However, there are toolchain issues that make that not work as well at | ||
// present (notably TSAN doesn't like it). | ||
return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1; | ||
} | ||
|
||
// Return whether the reference count is one. If the reference count is used | ||
// in the conventional way, a reference count of 1 implies that the current | ||
// thread owns the reference and no other thread shares it. This call | ||
// performs the test for a reference count of one, and performs the memory | ||
// barrier needed for the owning thread to act on the object, knowing that it | ||
// has exclusive access to the object. | ||
bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; } | ||
|
||
// Return whether the reference count is zero. With conventional object | ||
// referencing counting, the object will be destroyed, so the reference count | ||
// should never be zero. Hence this is generally used for a debug check. | ||
bool IsZero() const { | ||
return ref_count_.load(std::memory_order_acquire) == 0; | ||
} | ||
|
||
// Returns the current reference count (with no barriers). This is subtle, and | ||
// should be used only for debugging. | ||
int SubtleRefCountForDebug() const { | ||
return ref_count_.load(std::memory_order_relaxed); | ||
} | ||
|
||
private: | ||
std::atomic_int ref_count_; | ||
}; | ||
|
||
} // namespace partition_alloc::internal::base | ||
|
||
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_ATOMIC_REF_COUNT_H_ |
46 changes: 46 additions & 0 deletions
46
base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright (c) 2011 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 "base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h" | ||
|
||
#include <limits> | ||
#include <ostream> | ||
#include <type_traits> | ||
|
||
namespace partition_alloc::internal::base::subtle { | ||
|
||
bool RefCountedThreadSafeBase::HasOneRef() const { | ||
return ref_count_.IsOne(); | ||
} | ||
|
||
bool RefCountedThreadSafeBase::HasAtLeastOneRef() const { | ||
return !ref_count_.IsZero(); | ||
} | ||
|
||
#if DCHECK_IS_ON() | ||
RefCountedThreadSafeBase::~RefCountedThreadSafeBase() { | ||
DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without " | ||
"calling Release()"; | ||
} | ||
#endif | ||
|
||
// For security and correctness, we check the arithmetic on ref counts. | ||
// | ||
// In an attempt to avoid binary bloat (from inlining the `CHECK`), we define | ||
// these functions out-of-line. However, compilers are wily. Further testing may | ||
// show that `NOINLINE` helps or hurts. | ||
// | ||
#if !defined(ARCH_CPU_X86_FAMILY) | ||
bool RefCountedThreadSafeBase::Release() const { | ||
return ReleaseImpl(); | ||
} | ||
void RefCountedThreadSafeBase::AddRef() const { | ||
AddRefImpl(); | ||
} | ||
void RefCountedThreadSafeBase::AddRefWithCheck() const { | ||
AddRefWithCheckImpl(); | ||
} | ||
#endif | ||
|
||
} // namespace partition_alloc::internal::base::subtle |
188 changes: 188 additions & 0 deletions
188
base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
// Copyright (c) 2012 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ | ||
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ | ||
|
||
#include "base/allocator/partition_allocator/partition_alloc_base/atomic_ref_count.h" | ||
#include "base/allocator/partition_allocator/partition_alloc_base/memory/scoped_refptr.h" | ||
#include "base/base_export.h" | ||
#include "base/check.h" | ||
#include "base/check_op.h" | ||
#include "base/compiler_specific.h" | ||
#include "base/dcheck_is_on.h" | ||
#include "build/build_config.h" | ||
|
||
namespace partition_alloc::internal::base { | ||
namespace subtle { | ||
|
||
class BASE_EXPORT RefCountedThreadSafeBase { | ||
public: | ||
RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete; | ||
RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete; | ||
|
||
bool HasOneRef() const; | ||
bool HasAtLeastOneRef() const; | ||
|
||
protected: | ||
explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} | ||
explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) | ||
: ref_count_(1) { | ||
#if DCHECK_IS_ON() | ||
needs_adopt_ref_ = true; | ||
#endif | ||
} | ||
|
||
#if DCHECK_IS_ON() | ||
~RefCountedThreadSafeBase(); | ||
#else | ||
~RefCountedThreadSafeBase() = default; | ||
#endif | ||
|
||
// Release and AddRef are suitable for inlining on X86 because they generate | ||
// very small code sequences. On other platforms (ARM), it causes a size | ||
// regression and is probably not worth it. | ||
#if defined(ARCH_CPU_X86_FAMILY) | ||
// Returns true if the object should self-delete. | ||
bool Release() const { return ReleaseImpl(); } | ||
void AddRef() const { AddRefImpl(); } | ||
void AddRefWithCheck() const { AddRefWithCheckImpl(); } | ||
#else | ||
// Returns true if the object should self-delete. | ||
bool Release() const; | ||
void AddRef() const; | ||
void AddRefWithCheck() const; | ||
#endif | ||
|
||
private: | ||
template <typename U> | ||
friend scoped_refptr<U> AdoptRef(U*); | ||
|
||
void Adopted() const { | ||
#if DCHECK_IS_ON() | ||
DCHECK(needs_adopt_ref_); | ||
needs_adopt_ref_ = false; | ||
#endif | ||
} | ||
|
||
ALWAYS_INLINE void AddRefImpl() const { | ||
#if DCHECK_IS_ON() | ||
DCHECK(!in_dtor_); | ||
// This RefCounted object is created with non-zero reference count. | ||
// The first reference to such a object has to be made by AdoptRef or | ||
// MakeRefCounted. | ||
DCHECK(!needs_adopt_ref_); | ||
#endif | ||
ref_count_.Increment(); | ||
} | ||
|
||
ALWAYS_INLINE void AddRefWithCheckImpl() const { | ||
#if DCHECK_IS_ON() | ||
DCHECK(!in_dtor_); | ||
// This RefCounted object is created with non-zero reference count. | ||
// The first reference to such a object has to be made by AdoptRef or | ||
// MakeRefCounted. | ||
DCHECK(!needs_adopt_ref_); | ||
#endif | ||
CHECK_GT(ref_count_.Increment(), 0); | ||
} | ||
|
||
ALWAYS_INLINE bool ReleaseImpl() const { | ||
#if DCHECK_IS_ON() | ||
DCHECK(!in_dtor_); | ||
DCHECK(!ref_count_.IsZero()); | ||
#endif | ||
if (!ref_count_.Decrement()) { | ||
#if DCHECK_IS_ON() | ||
in_dtor_ = true; | ||
#endif | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
mutable AtomicRefCount ref_count_{0}; | ||
#if DCHECK_IS_ON() | ||
mutable bool needs_adopt_ref_ = false; | ||
mutable bool in_dtor_ = false; | ||
#endif | ||
}; | ||
|
||
} // namespace subtle | ||
|
||
// Forward declaration. | ||
template <class T, typename Traits> | ||
class RefCountedThreadSafe; | ||
|
||
// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref | ||
// count reaches 0. Overload to delete it on a different thread etc. | ||
template <typename T> | ||
struct DefaultRefCountedThreadSafeTraits { | ||
static void Destruct(const T* x) { | ||
// Delete through RefCountedThreadSafe to make child classes only need to be | ||
// friend with RefCountedThreadSafe instead of this struct, which is an | ||
// implementation detail. | ||
RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal( | ||
x); | ||
} | ||
}; | ||
|
||
// | ||
// A thread-safe variant of RefCounted<T> | ||
// | ||
// class MyFoo : public base::RefCountedThreadSafe<MyFoo> { | ||
// ... | ||
// }; | ||
// | ||
// If you're using the default trait, then you should add compile time | ||
// asserts that no one else is deleting your object. i.e. | ||
// private: | ||
// friend class base::RefCountedThreadSafe<MyFoo>; | ||
// ~MyFoo(); | ||
// | ||
// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe | ||
// too. See the comment above the RefCounted definition for details. | ||
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>> | ||
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | ||
public: | ||
static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = | ||
subtle::kStartRefCountFromZeroTag; | ||
|
||
explicit RefCountedThreadSafe() | ||
: subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} | ||
|
||
RefCountedThreadSafe(const RefCountedThreadSafe&) = delete; | ||
RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete; | ||
|
||
void AddRef() const { AddRefImpl(T::kRefCountPreference); } | ||
|
||
void Release() const { | ||
if (subtle::RefCountedThreadSafeBase::Release()) { | ||
ANALYZER_SKIP_THIS_PATH(); | ||
Traits::Destruct(static_cast<const T*>(this)); | ||
} | ||
} | ||
|
||
protected: | ||
~RefCountedThreadSafe() = default; | ||
|
||
private: | ||
friend struct DefaultRefCountedThreadSafeTraits<T>; | ||
template <typename U> | ||
static void DeleteInternal(const U* x) { | ||
delete x; | ||
} | ||
|
||
void AddRefImpl(subtle::StartRefCountFromZeroTag) const { | ||
subtle::RefCountedThreadSafeBase::AddRef(); | ||
} | ||
|
||
void AddRefImpl(subtle::StartRefCountFromOneTag) const { | ||
subtle::RefCountedThreadSafeBase::AddRefWithCheck(); | ||
} | ||
}; | ||
|
||
} // namespace partition_alloc::internal::base | ||
|
||
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ |
Oops, something went wrong.