mnaganov@chromium.org | 08a60f5 | 2012-01-05 19:52:55 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_MEMORY_REF_COUNTED_H_ |
| 6 | #define BASE_MEMORY_REF_COUNTED_H_ |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 7 | |
robpercival | b244434 | 2016-05-19 09:48:51 +0900 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | |
akalin@chromium.org | ee0b43d | 2012-01-31 11:16:55 +0900 | [diff] [blame] | 10 | #include <cassert> |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 11 | #include <iosfwd> |
piman | 5e31866 | 2016-04-20 10:04:40 +0900 | [diff] [blame] | 12 | #include <type_traits> |
akalin@chromium.org | ee0b43d | 2012-01-31 11:16:55 +0900 | [diff] [blame] | 13 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 14 | #include "base/atomic_ref_count.h" |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 15 | #include "base/base_export.h" |
xiaomings@google.com | b5c3d67 | 2012-08-29 05:19:51 +0900 | [diff] [blame] | 16 | #include "base/compiler_specific.h" |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 17 | #include "base/logging.h" |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 18 | #include "base/macros.h" |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 19 | #include "base/sequence_checker.h" |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 20 | #include "base/threading/thread_collision_warner.h" |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 21 | #include "build/build_config.h" |
| 22 | |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 23 | template <class T> |
| 24 | class scoped_refptr; |
| 25 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 26 | namespace base { |
| 27 | |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 28 | template <typename T> |
| 29 | scoped_refptr<T> AdoptRef(T* t); |
| 30 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 31 | namespace subtle { |
| 32 | |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 33 | enum AdoptRefTag { kAdoptRefTag }; |
| 34 | enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; |
| 35 | enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; |
| 36 | |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 37 | class BASE_EXPORT RefCountedBase { |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 38 | public: |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 39 | bool HasOneRef() const { return ref_count_ == 1; } |
| 40 | |
| 41 | protected: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 42 | explicit RefCountedBase(StartRefCountFromZeroTag) { |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 43 | #if DCHECK_IS_ON() |
| 44 | sequence_checker_.DetachFromSequence(); |
| 45 | #endif |
| 46 | } |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 47 | |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 48 | explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 49 | #if DCHECK_IS_ON() |
| 50 | needs_adopt_ref_ = true; |
| 51 | sequence_checker_.DetachFromSequence(); |
| 52 | #endif |
| 53 | } |
| 54 | |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 55 | ~RefCountedBase() { |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 56 | #if DCHECK_IS_ON() |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 57 | DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 58 | #endif |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 59 | } |
| 60 | |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 61 | void AddRef() const { |
| 62 | // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 63 | // Current thread books the critical section "AddRelease" |
| 64 | // without release it. |
| 65 | // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 66 | #if DCHECK_IS_ON() |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 67 | DCHECK(!in_dtor_); |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 68 | DCHECK(!needs_adopt_ref_) |
| 69 | << "This RefCounted object is created with non-zero reference count." |
| 70 | << " The first reference to such a object has to be made by AdoptRef or" |
Taiju Tsuiki | 6bd129a | 2017-05-18 15:45:43 +0900 | [diff] [blame] | 71 | << " MakeRefCounted."; |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 72 | if (ref_count_ >= 1) { |
| 73 | DCHECK(CalledOnValidSequence()); |
| 74 | } |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 75 | #endif |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 76 | |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 77 | ++ref_count_; |
| 78 | } |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 79 | |
| 80 | // Returns true if the object should self-delete. |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 81 | bool Release() const { |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 82 | --ref_count_; |
| 83 | |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 84 | // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 85 | // Current thread books the critical section "AddRelease" |
| 86 | // without release it. |
| 87 | // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 88 | |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 89 | #if DCHECK_IS_ON() |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 90 | DCHECK(!in_dtor_); |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 91 | if (ref_count_ == 0) |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 92 | in_dtor_ = true; |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 93 | |
| 94 | if (ref_count_ >= 1) |
| 95 | DCHECK(CalledOnValidSequence()); |
| 96 | if (ref_count_ == 1) |
| 97 | sequence_checker_.DetachFromSequence(); |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 98 | #endif |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 99 | |
| 100 | return ref_count_ == 0; |
mikhail.pozdnyakov@intel.com | d45f3e3 | 2013-12-20 05:48:41 +0900 | [diff] [blame] | 101 | } |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 102 | |
| 103 | private: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 104 | template <typename U> |
| 105 | friend scoped_refptr<U> base::AdoptRef(U*); |
| 106 | |
| 107 | void Adopted() const { |
| 108 | #if DCHECK_IS_ON() |
| 109 | DCHECK(needs_adopt_ref_); |
| 110 | needs_adopt_ref_ = false; |
| 111 | #endif |
| 112 | } |
| 113 | |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 114 | #if DCHECK_IS_ON() |
| 115 | bool CalledOnValidSequence() const; |
| 116 | #endif |
| 117 | |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 118 | mutable size_t ref_count_ = 0; |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 119 | |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 120 | #if DCHECK_IS_ON() |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 121 | mutable bool needs_adopt_ref_ = false; |
tzik | 08aaedd | 2017-03-31 00:13:25 +0900 | [diff] [blame] | 122 | mutable bool in_dtor_ = false; |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 123 | mutable SequenceChecker sequence_checker_; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 124 | #endif |
| 125 | |
| 126 | DFAKE_MUTEX(add_release_); |
| 127 | |
| 128 | DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
| 129 | }; |
| 130 | |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 131 | class BASE_EXPORT RefCountedThreadSafeBase { |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 132 | public: |
agrieve | a7fd5f1 | 2016-09-27 09:15:51 +0900 | [diff] [blame] | 133 | bool HasOneRef() const; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 134 | |
| 135 | protected: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 136 | explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} |
| 137 | explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 138 | #if DCHECK_IS_ON() |
| 139 | needs_adopt_ref_ = true; |
| 140 | #endif |
| 141 | } |
| 142 | |
agrieve | a7fd5f1 | 2016-09-27 09:15:51 +0900 | [diff] [blame] | 143 | ~RefCountedThreadSafeBase(); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 144 | |
agrieve | a7fd5f1 | 2016-09-27 09:15:51 +0900 | [diff] [blame] | 145 | void AddRef() const; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 146 | |
| 147 | // Returns true if the object should self-delete. |
agrieve | a7fd5f1 | 2016-09-27 09:15:51 +0900 | [diff] [blame] | 148 | bool Release() const; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 149 | |
| 150 | private: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 151 | template <typename U> |
| 152 | friend scoped_refptr<U> base::AdoptRef(U*); |
| 153 | |
| 154 | void Adopted() const { |
| 155 | #if DCHECK_IS_ON() |
| 156 | DCHECK(needs_adopt_ref_); |
| 157 | needs_adopt_ref_ = false; |
| 158 | #endif |
| 159 | } |
| 160 | |
tzik | 4f3e21e | 2017-03-03 04:26:16 +0900 | [diff] [blame] | 161 | mutable AtomicRefCount ref_count_ = 0; |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 162 | #if DCHECK_IS_ON() |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 163 | mutable bool needs_adopt_ref_ = false; |
tzik | 4f3e21e | 2017-03-03 04:26:16 +0900 | [diff] [blame] | 164 | mutable bool in_dtor_ = false; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 165 | #endif |
| 166 | |
| 167 | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
| 168 | }; |
| 169 | |
| 170 | } // namespace subtle |
| 171 | |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 172 | // ScopedAllowCrossThreadRefCountAccess disables the check documented on |
| 173 | // RefCounted below for rare pre-existing use cases where thread-safety was |
| 174 | // guaranteed through other means (e.g. explicit sequencing of calls across |
| 175 | // execution sequences when bouncing between threads in order). New callers |
| 176 | // should refrain from using this (callsites handling thread-safety through |
| 177 | // locks should use RefCountedThreadSafe per the overhead of its atomics being |
| 178 | // negligible compared to locks anyways and callsites doing explicit sequencing |
| 179 | // should properly std::move() the ref to avoid hitting this check). |
| 180 | // TODO(tzik): Cleanup existing use cases and remove |
| 181 | // ScopedAllowCrossThreadRefCountAccess. |
| 182 | class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final { |
| 183 | public: |
| 184 | #if DCHECK_IS_ON() |
| 185 | ScopedAllowCrossThreadRefCountAccess(); |
| 186 | ~ScopedAllowCrossThreadRefCountAccess(); |
| 187 | #else |
| 188 | ScopedAllowCrossThreadRefCountAccess() {} |
| 189 | ~ScopedAllowCrossThreadRefCountAccess() {} |
| 190 | #endif |
| 191 | }; |
| 192 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 193 | // |
| 194 | // A base class for reference counted classes. Otherwise, known as a cheap |
thakis | ab3fed8 | 2016-06-15 17:28:13 +0900 | [diff] [blame] | 195 | // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 196 | // class from it like so: |
| 197 | // |
| 198 | // class MyFoo : public base::RefCounted<MyFoo> { |
| 199 | // ... |
| 200 | // private: |
| 201 | // friend class base::RefCounted<MyFoo>; |
| 202 | // ~MyFoo(); |
| 203 | // }; |
| 204 | // |
hashimoto | cbfd67e | 2016-01-07 15:24:06 +0900 | [diff] [blame] | 205 | // You should always make your destructor non-public, to avoid any code deleting |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 206 | // the object accidently while there are references to it. |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 207 | // |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 208 | // |
tzik | 8a08348 | 2017-04-01 06:31:24 +0900 | [diff] [blame] | 209 | // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs |
| 210 | // to trap unsafe cross thread usage. A subclass instance of RefCounted can be |
| 211 | // passed to another execution sequence only when its ref count is 1. If the ref |
| 212 | // count is more than 1, the RefCounted class verifies the ref updates are made |
| 213 | // on the same execution sequence as the previous ones. |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 214 | // |
| 215 | // |
| 216 | // The reference count starts from zero by default, and we intended to migrate |
| 217 | // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to |
| 218 | // the ref counted class to opt-in. |
| 219 | // |
| 220 | // If an object has start-from-one ref count, the first scoped_refptr need to be |
Taiju Tsuiki | 6bd129a | 2017-05-18 15:45:43 +0900 | [diff] [blame] | 221 | // created by base::AdoptRef() or base::MakeRefCounted(). We can use |
| 222 | // base::MakeRefCounted() to create create both type of ref counted object. |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 223 | // |
| 224 | // The motivations to use start-from-one ref count are: |
| 225 | // - Start-from-one ref count doesn't need the ref count increment for the |
| 226 | // first reference. |
| 227 | // - It can detect an invalid object acquisition for a being-deleted object |
| 228 | // that has zero ref count. That tends to happen on custom deleter that |
| 229 | // delays the deletion. |
| 230 | // TODO(tzik): Implement invalid acquisition detection. |
| 231 | // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. |
| 232 | // And start-from-one ref count is a step to merge WTF::RefCounted into |
| 233 | // base::RefCounted. |
| 234 | // |
| 235 | #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ |
| 236 | static constexpr ::base::subtle::StartRefCountFromOneTag \ |
| 237 | kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag |
| 238 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 239 | template <class T> |
| 240 | class RefCounted : public subtle::RefCountedBase { |
| 241 | public: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 242 | static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 243 | subtle::kStartRefCountFromZeroTag; |
| 244 | |
| 245 | RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 246 | |
| 247 | void AddRef() const { |
| 248 | subtle::RefCountedBase::AddRef(); |
| 249 | } |
| 250 | |
| 251 | void Release() const { |
| 252 | if (subtle::RefCountedBase::Release()) { |
| 253 | delete static_cast<const T*>(this); |
| 254 | } |
| 255 | } |
| 256 | |
rsleevi@chromium.org | d55e9a4 | 2012-06-26 15:23:00 +0900 | [diff] [blame] | 257 | protected: |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 258 | ~RefCounted() = default; |
rsleevi@chromium.org | d55e9a4 | 2012-06-26 15:23:00 +0900 | [diff] [blame] | 259 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 260 | private: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 261 | DISALLOW_COPY_AND_ASSIGN(RefCounted); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 262 | }; |
| 263 | |
| 264 | // Forward declaration. |
| 265 | template <class T, typename Traits> class RefCountedThreadSafe; |
| 266 | |
| 267 | // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
| 268 | // count reaches 0. Overload to delete it on a different thread etc. |
| 269 | template<typename T> |
| 270 | struct DefaultRefCountedThreadSafeTraits { |
| 271 | static void Destruct(const T* x) { |
| 272 | // Delete through RefCountedThreadSafe to make child classes only need to be |
| 273 | // friend with RefCountedThreadSafe instead of this struct, which is an |
| 274 | // implementation detail. |
| 275 | RefCountedThreadSafe<T, |
| 276 | DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); |
| 277 | } |
| 278 | }; |
| 279 | |
| 280 | // |
| 281 | // A thread-safe variant of RefCounted<T> |
| 282 | // |
| 283 | // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { |
| 284 | // ... |
| 285 | // }; |
| 286 | // |
| 287 | // If you're using the default trait, then you should add compile time |
| 288 | // asserts that no one else is deleting your object. i.e. |
| 289 | // private: |
| 290 | // friend class base::RefCountedThreadSafe<MyFoo>; |
| 291 | // ~MyFoo(); |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 292 | // |
| 293 | // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe |
| 294 | // too. See the comment above the RefCounted definition for details. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 295 | template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
| 296 | class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
| 297 | public: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 298 | static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 299 | subtle::kStartRefCountFromZeroTag; |
| 300 | |
| 301 | explicit RefCountedThreadSafe() |
| 302 | : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 303 | |
| 304 | void AddRef() const { |
| 305 | subtle::RefCountedThreadSafeBase::AddRef(); |
| 306 | } |
| 307 | |
| 308 | void Release() const { |
| 309 | if (subtle::RefCountedThreadSafeBase::Release()) { |
| 310 | Traits::Destruct(static_cast<const T*>(this)); |
| 311 | } |
| 312 | } |
| 313 | |
rsleevi@chromium.org | d55e9a4 | 2012-06-26 15:23:00 +0900 | [diff] [blame] | 314 | protected: |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 315 | ~RefCountedThreadSafe() = default; |
rsleevi@chromium.org | d55e9a4 | 2012-06-26 15:23:00 +0900 | [diff] [blame] | 316 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 317 | private: |
| 318 | friend struct DefaultRefCountedThreadSafeTraits<T>; |
| 319 | static void DeleteInternal(const T* x) { delete x; } |
| 320 | |
| 321 | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); |
| 322 | }; |
| 323 | |
| 324 | // |
akalin@chromium.org | 4c0f060 | 2012-11-14 19:05:22 +0900 | [diff] [blame] | 325 | // A thread-safe wrapper for some piece of data so we can place other |
| 326 | // things in scoped_refptrs<>. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 327 | // |
| 328 | template<typename T> |
akalin@chromium.org | 4c0f060 | 2012-11-14 19:05:22 +0900 | [diff] [blame] | 329 | class RefCountedData |
| 330 | : public base::RefCountedThreadSafe< base::RefCountedData<T> > { |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 331 | public: |
| 332 | RefCountedData() : data() {} |
| 333 | RefCountedData(const T& in_value) : data(in_value) {} |
| 334 | |
| 335 | T data; |
rsleevi@chromium.org | 3c3d937 | 2012-06-25 17:15:42 +0900 | [diff] [blame] | 336 | |
| 337 | private: |
akalin@chromium.org | 4c0f060 | 2012-11-14 19:05:22 +0900 | [diff] [blame] | 338 | friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 339 | ~RefCountedData() = default; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 340 | }; |
| 341 | |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 342 | // Creates a scoped_refptr from a raw pointer without incrementing the reference |
| 343 | // count. Use this only for a newly created object whose reference count starts |
| 344 | // from 1 instead of 0. |
| 345 | template <typename T> |
| 346 | scoped_refptr<T> AdoptRef(T* obj) { |
| 347 | using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type; |
| 348 | static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value, |
| 349 | "Use AdoptRef only for the reference count starts from one."); |
| 350 | |
| 351 | DCHECK(obj); |
| 352 | DCHECK(obj->HasOneRef()); |
| 353 | obj->Adopted(); |
| 354 | return scoped_refptr<T>(obj, subtle::kAdoptRefTag); |
| 355 | } |
| 356 | |
| 357 | namespace subtle { |
| 358 | |
| 359 | template <typename T> |
| 360 | scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { |
| 361 | return scoped_refptr<T>(obj); |
| 362 | } |
| 363 | |
| 364 | template <typename T> |
| 365 | scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { |
| 366 | return AdoptRef(obj); |
| 367 | } |
| 368 | |
| 369 | } // namespace subtle |
| 370 | |
| 371 | // Constructs an instance of T, which is a ref counted type, and wraps the |
| 372 | // object into a scoped_refptr. |
| 373 | template <typename T, typename... Args> |
Taiju Tsuiki | 6bd129a | 2017-05-18 15:45:43 +0900 | [diff] [blame] | 374 | scoped_refptr<T> MakeRefCounted(Args&&... args) { |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 375 | T* obj = new T(std::forward<Args>(args)...); |
| 376 | return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); |
| 377 | } |
| 378 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 379 | } // namespace base |
| 380 | |
| 381 | // |
| 382 | // A smart pointer class for reference counted objects. Use this class instead |
| 383 | // of calling AddRef and Release manually on a reference counted object to |
| 384 | // avoid common memory leaks caused by forgetting to Release an object |
| 385 | // reference. Sample usage: |
| 386 | // |
| 387 | // class MyFoo : public RefCounted<MyFoo> { |
| 388 | // ... |
tnagel | b5d98a3 | 2016-12-01 10:19:50 +0900 | [diff] [blame] | 389 | // private: |
| 390 | // friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>. |
| 391 | // ~MyFoo(); // Destructor must be private/protected. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 392 | // }; |
| 393 | // |
| 394 | // void some_function() { |
| 395 | // scoped_refptr<MyFoo> foo = new MyFoo(); |
| 396 | // foo->Method(param); |
| 397 | // // |foo| is released when this function returns |
| 398 | // } |
| 399 | // |
| 400 | // void some_other_function() { |
| 401 | // scoped_refptr<MyFoo> foo = new MyFoo(); |
| 402 | // ... |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 403 | // foo = nullptr; // explicitly releases |foo| |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 404 | // ... |
| 405 | // if (foo) |
| 406 | // foo->Method(param); |
| 407 | // } |
| 408 | // |
| 409 | // The above examples show how scoped_refptr<T> acts like a pointer to T. |
| 410 | // Given two scoped_refptr<T> classes, it is also possible to exchange |
| 411 | // references between the two objects, like so: |
| 412 | // |
| 413 | // { |
| 414 | // scoped_refptr<MyFoo> a = new MyFoo(); |
| 415 | // scoped_refptr<MyFoo> b; |
| 416 | // |
| 417 | // b.swap(a); |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 418 | // // now, |b| references the MyFoo object, and |a| references nullptr. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 419 | // } |
| 420 | // |
| 421 | // To make both |a| and |b| in the above example reference the same MyFoo |
| 422 | // object, simply use the assignment operator: |
| 423 | // |
| 424 | // { |
| 425 | // scoped_refptr<MyFoo> a = new MyFoo(); |
| 426 | // scoped_refptr<MyFoo> b; |
| 427 | // |
| 428 | // b = a; |
| 429 | // // now, |a| and |b| each own a reference to the same MyFoo object. |
| 430 | // } |
| 431 | // |
| 432 | template <class T> |
| 433 | class scoped_refptr { |
| 434 | public: |
xhwang@chromium.org | 87cb6e3 | 2012-06-20 03:33:38 +0900 | [diff] [blame] | 435 | typedef T element_type; |
| 436 | |
gab | ab54585 | 2016-11-01 02:03:20 +0900 | [diff] [blame] | 437 | scoped_refptr() {} |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 438 | |
| 439 | scoped_refptr(T* p) : ptr_(p) { |
| 440 | if (ptr_) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 441 | AddRef(ptr_); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 442 | } |
| 443 | |
danakj | 1a33614 | 2015-12-05 05:12:27 +0900 | [diff] [blame] | 444 | // Copy constructor. |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 445 | scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
| 446 | if (ptr_) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 447 | AddRef(ptr_); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 448 | } |
| 449 | |
danakj | 1a33614 | 2015-12-05 05:12:27 +0900 | [diff] [blame] | 450 | // Copy conversion constructor. |
piman | 5e31866 | 2016-04-20 10:04:40 +0900 | [diff] [blame] | 451 | template <typename U, |
| 452 | typename = typename std::enable_if< |
| 453 | std::is_convertible<U*, T*>::value>::type> |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 454 | scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { |
| 455 | if (ptr_) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 456 | AddRef(ptr_); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 457 | } |
| 458 | |
danakj | 1a33614 | 2015-12-05 05:12:27 +0900 | [diff] [blame] | 459 | // Move constructor. This is required in addition to the conversion |
| 460 | // constructor below in order for clang to warn about pessimizing moves. |
| 461 | scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } |
| 462 | |
| 463 | // Move conversion constructor. |
piman | 5e31866 | 2016-04-20 10:04:40 +0900 | [diff] [blame] | 464 | template <typename U, |
| 465 | typename = typename std::enable_if< |
| 466 | std::is_convertible<U*, T*>::value>::type> |
kkimlabs | 56bcfba | 2015-04-14 05:49:43 +0900 | [diff] [blame] | 467 | scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { |
| 468 | r.ptr_ = nullptr; |
| 469 | } |
| 470 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 471 | ~scoped_refptr() { |
| 472 | if (ptr_) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 473 | Release(ptr_); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 474 | } |
| 475 | |
| 476 | T* get() const { return ptr_; } |
mikhail.pozdnyakov@intel.com | 3d81572 | 2013-10-21 23:16:31 +0900 | [diff] [blame] | 477 | |
dcheng | 8d031e1 | 2014-08-26 17:37:27 +0900 | [diff] [blame] | 478 | T& operator*() const { |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 479 | assert(ptr_ != nullptr); |
dcheng | 8d031e1 | 2014-08-26 17:37:27 +0900 | [diff] [blame] | 480 | return *ptr_; |
| 481 | } |
| 482 | |
akalin@chromium.org | ee0b43d | 2012-01-31 11:16:55 +0900 | [diff] [blame] | 483 | T* operator->() const { |
gab | 9ef4fb6 | 2016-10-28 04:06:02 +0900 | [diff] [blame] | 484 | assert(ptr_ != nullptr); |
akalin@chromium.org | ee0b43d | 2012-01-31 11:16:55 +0900 | [diff] [blame] | 485 | return ptr_; |
| 486 | } |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 487 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 488 | scoped_refptr<T>& operator=(T* p) { |
| 489 | // AddRef first so that self assignment should work |
| 490 | if (p) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 491 | AddRef(p); |
mnaganov@chromium.org | 08a60f5 | 2012-01-05 19:52:55 +0900 | [diff] [blame] | 492 | T* old_ptr = ptr_; |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 493 | ptr_ = p; |
mnaganov@chromium.org | 08a60f5 | 2012-01-05 19:52:55 +0900 | [diff] [blame] | 494 | if (old_ptr) |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 495 | Release(old_ptr); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 496 | return *this; |
| 497 | } |
| 498 | |
| 499 | scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { |
| 500 | return *this = r.ptr_; |
| 501 | } |
| 502 | |
| 503 | template <typename U> |
| 504 | scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
| 505 | return *this = r.get(); |
| 506 | } |
| 507 | |
kkimlabs | 56bcfba | 2015-04-14 05:49:43 +0900 | [diff] [blame] | 508 | scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { |
danakj | 800d2ea | 2015-11-25 14:29:58 +0900 | [diff] [blame] | 509 | scoped_refptr<T>(std::move(r)).swap(*this); |
kkimlabs | 56bcfba | 2015-04-14 05:49:43 +0900 | [diff] [blame] | 510 | return *this; |
| 511 | } |
| 512 | |
| 513 | template <typename U> |
| 514 | scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { |
danakj | 800d2ea | 2015-11-25 14:29:58 +0900 | [diff] [blame] | 515 | scoped_refptr<T>(std::move(r)).swap(*this); |
kkimlabs | 56bcfba | 2015-04-14 05:49:43 +0900 | [diff] [blame] | 516 | return *this; |
| 517 | } |
| 518 | |
estevenson | 0976cc1 | 2017-03-09 00:31:29 +0900 | [diff] [blame] | 519 | void swap(scoped_refptr<T>& r) { |
tzik | a513a31 | 2017-03-14 22:27:36 +0900 | [diff] [blame] | 520 | T* tmp = ptr_; |
| 521 | ptr_ = r.ptr_; |
| 522 | r.ptr_ = tmp; |
estevenson | 0976cc1 | 2017-03-09 00:31:29 +0900 | [diff] [blame] | 523 | } |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 524 | |
scheib | d8068c4 | 2016-05-12 15:18:46 +0900 | [diff] [blame] | 525 | explicit operator bool() const { return ptr_ != nullptr; } |
dcheng | 5c3b6f3 | 2014-11-26 11:35:08 +0900 | [diff] [blame] | 526 | |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 527 | template <typename U> |
| 528 | bool operator==(const scoped_refptr<U>& rhs) const { |
| 529 | return ptr_ == rhs.get(); |
| 530 | } |
| 531 | |
| 532 | template <typename U> |
| 533 | bool operator!=(const scoped_refptr<U>& rhs) const { |
| 534 | return !operator==(rhs); |
| 535 | } |
| 536 | |
| 537 | template <typename U> |
| 538 | bool operator<(const scoped_refptr<U>& rhs) const { |
| 539 | return ptr_ < rhs.get(); |
| 540 | } |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 541 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 542 | protected: |
gab | ab54585 | 2016-11-01 02:03:20 +0900 | [diff] [blame] | 543 | T* ptr_ = nullptr; |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 544 | |
| 545 | private: |
tzik | bfc6770 | 2017-04-03 14:27:34 +0900 | [diff] [blame] | 546 | template <typename U> |
| 547 | friend scoped_refptr<U> base::AdoptRef(U*); |
| 548 | |
| 549 | scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} |
| 550 | |
scheib | d8068c4 | 2016-05-12 15:18:46 +0900 | [diff] [blame] | 551 | // Friend required for move constructors that set r.ptr_ to null. |
| 552 | template <typename U> |
| 553 | friend class scoped_refptr; |
| 554 | |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 555 | // Non-inline helpers to allow: |
| 556 | // class Opaque; |
| 557 | // extern template class scoped_refptr<Opaque>; |
| 558 | // Otherwise the compiler will complain that Opaque is an incomplete type. |
| 559 | static void AddRef(T* ptr); |
| 560 | static void Release(T* ptr); |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 561 | }; |
| 562 | |
gab | 351b98b | 2016-11-01 23:13:20 +0900 | [diff] [blame] | 563 | // static |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 564 | template <typename T> |
| 565 | void scoped_refptr<T>::AddRef(T* ptr) { |
| 566 | ptr->AddRef(); |
| 567 | } |
| 568 | |
gab | 351b98b | 2016-11-01 23:13:20 +0900 | [diff] [blame] | 569 | // static |
mdempsky | 46ffec3 | 2014-10-10 07:17:09 +0900 | [diff] [blame] | 570 | template <typename T> |
| 571 | void scoped_refptr<T>::Release(T* ptr) { |
| 572 | ptr->Release(); |
| 573 | } |
| 574 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 575 | // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
| 576 | // having to retype all the template arguments |
| 577 | template <typename T> |
| 578 | scoped_refptr<T> make_scoped_refptr(T* t) { |
| 579 | return scoped_refptr<T>(t); |
| 580 | } |
| 581 | |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 582 | template <typename T, typename U> |
| 583 | bool operator==(const scoped_refptr<T>& lhs, const U* rhs) { |
| 584 | return lhs.get() == rhs; |
| 585 | } |
| 586 | |
| 587 | template <typename T, typename U> |
| 588 | bool operator==(const T* lhs, const scoped_refptr<U>& rhs) { |
| 589 | return lhs == rhs.get(); |
| 590 | } |
| 591 | |
robpercival | b244434 | 2016-05-19 09:48:51 +0900 | [diff] [blame] | 592 | template <typename T> |
| 593 | bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) { |
| 594 | return !static_cast<bool>(lhs); |
| 595 | } |
| 596 | |
| 597 | template <typename T> |
| 598 | bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 599 | return !static_cast<bool>(rhs); |
| 600 | } |
| 601 | |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 602 | template <typename T, typename U> |
| 603 | bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) { |
| 604 | return !operator==(lhs, rhs); |
| 605 | } |
| 606 | |
| 607 | template <typename T, typename U> |
| 608 | bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) { |
| 609 | return !operator==(lhs, rhs); |
| 610 | } |
| 611 | |
| 612 | template <typename T> |
robpercival | b244434 | 2016-05-19 09:48:51 +0900 | [diff] [blame] | 613 | bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) { |
| 614 | return !operator==(lhs, null); |
| 615 | } |
| 616 | |
| 617 | template <typename T> |
| 618 | bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 619 | return !operator==(null, rhs); |
| 620 | } |
| 621 | |
| 622 | template <typename T> |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 623 | std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
| 624 | return out << p.get(); |
| 625 | } |
Daniel Cheng | 8f6c3bf | 2014-09-05 16:16:45 +0900 | [diff] [blame] | 626 | |
levin@chromium.org | 5c52868 | 2011-03-28 10:54:15 +0900 | [diff] [blame] | 627 | #endif // BASE_MEMORY_REF_COUNTED_H_ |