WeakPtr.h (12332B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Weak pointer functionality, implemented as a mixin for use with any class. */ 8 9 /** 10 * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting 11 * its lifetime. It works by creating a single shared reference counted object 12 * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo' 13 * clear the pointer in the WeakReference without having to know about all of 14 * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime 15 * of 'Foo'. 16 * 17 * PLEASE NOTE: This weak pointer implementation is not thread-safe. 18 * 19 * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional 20 * dereference, and an additional heap allocated pointer sized object shared 21 * between all of the WeakPtrs. 22 * 23 * Example of usage: 24 * 25 * // To have a class C support weak pointers, inherit from 26 * // SupportsWeakPtr 27 * class C : public SupportsWeakPtr 28 * { 29 * public: 30 * int mNum; 31 * void act(); 32 * }; 33 * 34 * C* ptr = new C(); 35 * 36 * // Get weak pointers to ptr. The first time a weak pointer 37 * // is obtained, a reference counted WeakReference object is created that 38 * // can live beyond the lifetime of 'ptr'. The WeakReference 39 * // object will be notified of 'ptr's destruction. 40 * WeakPtr<C> weak = ptr; 41 * WeakPtr<C> other = ptr; 42 * 43 * // Test a weak pointer for validity before using it. 44 * if (weak) { 45 * weak->mNum = 17; 46 * weak->act(); 47 * } 48 * 49 * // Destroying the underlying object clears weak pointers to it. 50 * delete ptr; 51 * 52 * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); 53 * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); 54 * 55 * WeakPtr is typesafe and may be used with any class. It is not required that 56 * the class be reference-counted or allocated in any particular way. 57 * 58 * The API was loosely inspired by Chromium's weak_ptr.h: 59 * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h 60 * 61 * Note that multiple base classes inheriting from SupportsWeakPtr is not 62 * currently supported. We could support it if needed though. 63 * 64 * For Gecko-internal usage there is also MainThreadWeakPtr<T>, a version of 65 * WeakPtr that can be destroyed on any thread, but whose release gets proxied 66 * to the main thread. This is a similar API to nsMainThreadPtrHandle, but 67 * without keeping a strong reference to the main-thread object. Said WeakPtr 68 * can't be accessed from any other thread that isn't the main thread. 69 */ 70 71 #ifndef mozilla_WeakPtr_h 72 #define mozilla_WeakPtr_h 73 74 #include "mozilla/Assertions.h" 75 #include "mozilla/Attributes.h" 76 #include "mozilla/Maybe.h" 77 #include "mozilla/RefCounted.h" 78 #include "mozilla/RefPtr.h" 79 80 #include <string.h> 81 82 #if defined(MOZILLA_INTERNAL_API) 83 // For thread safety checking. 84 # include "nsISupportsImpl.h" 85 // For main thread destructor behavior. 86 # include "nsProxyRelease.h" 87 #endif 88 89 #if defined(MOZILLA_INTERNAL_API) && \ 90 defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED) 91 92 // Weak referencing is not implemented as thread safe. When a WeakPtr 93 // is created or dereferenced on thread A but the real object is just 94 // being Released() on thread B, there is a possibility of a race 95 // when the proxy object (detail::WeakReference) is notified about 96 // the real object destruction just between when thread A is storing 97 // the object pointer locally and is about to add a reference to it. 98 // 99 // Hence, a non-null weak proxy object is considered to have a single 100 // "owning thread". It means that each query for a weak reference, 101 // its dereference, and destruction of the real object must all happen 102 // on a single thread. The following macros implement assertions for 103 // checking these conditions. 104 // 105 // We re-use XPCOM's nsAutoOwningEventTarget checks when they are available. 106 // This has the advantage that it works with cooperative thread pools. 107 108 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \ 109 /* Will be none if mPtr = nullptr. */ \ 110 Maybe<nsAutoOwningEventTarget> _owningThread; 111 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ 112 do { \ 113 if (p) { \ 114 _owningThread.emplace(); \ 115 } \ 116 } while (false) 117 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ 118 do { \ 119 MOZ_DIAGNOSTIC_ASSERT( \ 120 !_owningThread || _owningThread->IsCurrentThread(), \ 121 "WeakPtr accessed from multiple threads"); \ 122 } while (false) 123 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \ 124 (that)->AssertThreadSafety(); 125 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \ 126 do { \ 127 if (that) { \ 128 (that)->AssertThreadSafety(); \ 129 } \ 130 } while (false) 131 132 # define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1 133 134 #else 135 136 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK 137 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ 138 do { \ 139 } while (false) 140 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ 141 do { \ 142 } while (false) 143 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \ 144 do { \ 145 } while (false) 146 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \ 147 do { \ 148 } while (false) 149 150 #endif 151 152 namespace mozilla { 153 154 namespace detail { 155 156 enum class WeakPtrDestructorBehavior { 157 Normal, 158 #ifdef MOZILLA_INTERNAL_API 159 ProxyToMainThread, 160 #endif 161 }; 162 163 } // namespace detail 164 165 template <typename T, detail::WeakPtrDestructorBehavior = 166 detail::WeakPtrDestructorBehavior::Normal> 167 class WeakPtr; 168 class SupportsWeakPtr; 169 170 namespace detail { 171 172 // This can live beyond the lifetime of the class derived from 173 // SupportsWeakPtr. 174 class WeakReference : public ::mozilla::RefCounted<WeakReference> { 175 public: 176 explicit WeakReference(const SupportsWeakPtr* p) 177 : mPtr(const_cast<SupportsWeakPtr*>(p)) { 178 MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK(); 179 } 180 181 SupportsWeakPtr* get() const { 182 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); 183 return mPtr; 184 } 185 186 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING 187 const char* typeName() const { return "WeakReference"; } 188 size_t typeSize() const { return sizeof(*this); } 189 #endif 190 191 #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 192 void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); } 193 #endif 194 195 private: 196 friend class mozilla::SupportsWeakPtr; 197 198 void detach() { 199 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); 200 mPtr = nullptr; 201 } 202 203 SupportsWeakPtr* MOZ_NON_OWNING_REF mPtr; 204 MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK 205 }; 206 207 } // namespace detail 208 209 class SupportsWeakPtr { 210 using WeakReference = detail::WeakReference; 211 212 protected: 213 ~SupportsWeakPtr() { DetachWeakPtr(); } 214 215 protected: 216 void DetachWeakPtr() { 217 if (mSelfReferencingWeakReference) { 218 mSelfReferencingWeakReference->detach(); 219 } 220 } 221 222 private: 223 WeakReference* SelfReferencingWeakReference() const { 224 if (!mSelfReferencingWeakReference) { 225 mSelfReferencingWeakReference = new WeakReference(this); 226 } else { 227 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakReference); 228 } 229 return mSelfReferencingWeakReference.get(); 230 } 231 232 template <typename U, detail::WeakPtrDestructorBehavior> 233 friend class WeakPtr; 234 235 mutable RefPtr<WeakReference> mSelfReferencingWeakReference; 236 }; 237 238 template <typename T, detail::WeakPtrDestructorBehavior Destruct> 239 class WeakPtr { 240 using WeakReference = detail::WeakReference; 241 242 public: 243 WeakPtr& operator=(const WeakPtr& aOther) { 244 // We must make sure the reference we have now is safe to be dereferenced 245 // before we throw it away... (this can be called from a ctor) 246 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef); 247 // ...and make sure the new reference is used on a single thread as well. 248 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(aOther.mRef); 249 250 mRef = aOther.mRef; 251 return *this; 252 } 253 254 WeakPtr(const WeakPtr& aOther) { 255 // The thread safety check is performed inside of the operator= method. 256 *this = aOther; 257 } 258 259 WeakPtr& operator=(decltype(nullptr)) { 260 // We must make sure the reference we have now is safe to be dereferenced 261 // before we throw it away. 262 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef); 263 if (!mRef || mRef->get()) { 264 // Ensure that mRef is dereferenceable in the uninitialized state. 265 mRef = new WeakReference(nullptr); 266 } 267 return *this; 268 } 269 270 WeakPtr& operator=(const T* aOther) { 271 // We must make sure the reference we have now is safe to be dereferenced 272 // before we throw it away. 273 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef); 274 if (aOther) { 275 mRef = aOther->SelfReferencingWeakReference(); 276 } else if (!mRef || mRef->get()) { 277 // Ensure that mRef is dereferenceable in the uninitialized state. 278 mRef = new WeakReference(nullptr); 279 } 280 // The thread safety check happens inside SelfReferencingWeakPtr 281 // or is initialized in the WeakReference constructor. 282 return *this; 283 } 284 285 MOZ_IMPLICIT WeakPtr(T* aOther) { 286 *this = aOther; 287 #ifdef MOZILLA_INTERNAL_API 288 if (Destruct == detail::WeakPtrDestructorBehavior::ProxyToMainThread) { 289 MOZ_ASSERT(NS_IsMainThread(), 290 "MainThreadWeakPtr makes no sense on non-main threads"); 291 } 292 #endif 293 } 294 295 explicit WeakPtr(const RefPtr<T>& aOther) : WeakPtr(aOther.get()) {} 296 297 // Ensure that mRef is dereferenceable in the uninitialized state. 298 WeakPtr() : mRef(new WeakReference(nullptr)) {} 299 300 explicit operator bool() const { return mRef->get(); } 301 T* get() const { return static_cast<T*>(mRef->get()); } 302 operator T*() const { return get(); } 303 T& operator*() const { return *get(); } 304 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return get(); } 305 306 #ifdef MOZILLA_INTERNAL_API 307 ~WeakPtr() { 308 if (Destruct == detail::WeakPtrDestructorBehavior::ProxyToMainThread) { 309 NS_ReleaseOnMainThread("WeakPtr::mRef", mRef.forget()); 310 } else { 311 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); 312 } 313 } 314 #endif 315 316 private: 317 friend class SupportsWeakPtr; 318 319 explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {} 320 321 RefPtr<WeakReference> mRef; 322 }; 323 324 #ifdef MOZILLA_INTERNAL_API 325 326 template <typename T> 327 using MainThreadWeakPtr = 328 WeakPtr<T, detail::WeakPtrDestructorBehavior::ProxyToMainThread>; 329 330 #endif 331 332 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR tmp->DetachWeakPtr(); 333 334 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR(class_, ...) \ 335 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \ 336 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(class_) \ 337 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \ 338 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \ 339 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ 340 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(class_) \ 341 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ 342 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 343 344 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(class_, super_, ...) \ 345 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \ 346 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(class_, super_) \ 347 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \ 348 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \ 349 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ 350 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(class_, super_) \ 351 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ 352 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 353 354 } // namespace mozilla 355 356 #endif /* mozilla_WeakPtr_h */