ThreadSafeWeakPtr.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Weakable.h>
  8. namespace AK {
  9. template<typename T>
  10. class [[nodiscard]] WeakPtr {
  11. template<typename U>
  12. friend class Weakable;
  13. public:
  14. WeakPtr() = default;
  15. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  16. WeakPtr(const WeakPtr<U>& other)
  17. : m_link(other.m_link)
  18. {
  19. }
  20. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  21. WeakPtr(WeakPtr<U>&& other)
  22. : m_link(other.take_link())
  23. {
  24. }
  25. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  26. WeakPtr& operator=(WeakPtr<U>&& other)
  27. {
  28. m_link = other.take_link();
  29. return *this;
  30. }
  31. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  32. WeakPtr& operator=(const WeakPtr<U>& other)
  33. {
  34. if ((const void*)this != (const void*)&other)
  35. m_link = other.m_link;
  36. return *this;
  37. }
  38. WeakPtr& operator=(std::nullptr_t)
  39. {
  40. clear();
  41. return *this;
  42. }
  43. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  44. WeakPtr(const U& object)
  45. : m_link(object.template make_weak_ptr<U>().take_link())
  46. {
  47. }
  48. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  49. WeakPtr(const U* object)
  50. {
  51. if (object)
  52. m_link = object->template make_weak_ptr<U>().take_link();
  53. }
  54. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  55. WeakPtr(const RefPtr<U>& object)
  56. {
  57. object.do_while_locked([&](U* obj) {
  58. if (obj)
  59. m_link = obj->template make_weak_ptr<U>().take_link();
  60. });
  61. }
  62. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  63. WeakPtr(const NonnullRefPtr<U>& object)
  64. {
  65. object.do_while_locked([&](U* obj) {
  66. if (obj)
  67. m_link = obj->template make_weak_ptr<U>().take_link();
  68. });
  69. }
  70. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  71. WeakPtr& operator=(const U& object)
  72. {
  73. m_link = object.template make_weak_ptr<U>().take_link();
  74. return *this;
  75. }
  76. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  77. WeakPtr& operator=(const U* object)
  78. {
  79. if (object)
  80. m_link = object->template make_weak_ptr<U>().take_link();
  81. else
  82. m_link = nullptr;
  83. return *this;
  84. }
  85. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  86. WeakPtr& operator=(const RefPtr<U>& object)
  87. {
  88. object.do_while_locked([&](U* obj) {
  89. if (obj)
  90. m_link = obj->template make_weak_ptr<U>().take_link();
  91. else
  92. m_link = nullptr;
  93. });
  94. return *this;
  95. }
  96. template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
  97. WeakPtr& operator=(const NonnullRefPtr<U>& object)
  98. {
  99. object.do_while_locked([&](U* obj) {
  100. if (obj)
  101. m_link = obj->template make_weak_ptr<U>().take_link();
  102. else
  103. m_link = nullptr;
  104. });
  105. return *this;
  106. }
  107. [[nodiscard]] RefPtr<T> strong_ref() const
  108. {
  109. // This only works with RefCounted objects, but it is the only
  110. // safe way to get a strong reference from a WeakPtr. Any code
  111. // that uses objects not derived from RefCounted will have to
  112. // use unsafe_ptr(), but as the name suggests, it is not safe...
  113. RefPtr<T> ref;
  114. // Using do_while_locked protects against a race with clear()!
  115. m_link.do_while_locked([&](WeakLink* link) {
  116. if (link)
  117. ref = link->template strong_ref<T>();
  118. });
  119. return ref;
  120. }
  121. #ifndef KERNEL
  122. // A lot of user mode code is single-threaded. But for kernel mode code
  123. // this is generally not true as everything is multi-threaded. So make
  124. // these shortcuts and aliases only available to non-kernel code.
  125. T* ptr() const { return unsafe_ptr(); }
  126. T* operator->() { return unsafe_ptr(); }
  127. const T* operator->() const { return unsafe_ptr(); }
  128. operator const T*() const { return unsafe_ptr(); }
  129. operator T*() { return unsafe_ptr(); }
  130. #endif
  131. [[nodiscard]] T* unsafe_ptr() const
  132. {
  133. T* ptr = nullptr;
  134. m_link.do_while_locked([&](WeakLink* link) {
  135. if (link)
  136. ptr = link->unsafe_ptr<T>();
  137. });
  138. return ptr;
  139. }
  140. operator bool() const { return m_link ? !m_link->is_null() : false; }
  141. [[nodiscard]] bool is_null() const { return !m_link || m_link->is_null(); }
  142. void clear() { m_link = nullptr; }
  143. [[nodiscard]] RefPtr<WeakLink> take_link() { return move(m_link); }
  144. private:
  145. WeakPtr(const RefPtr<WeakLink>& link)
  146. : m_link(link)
  147. {
  148. }
  149. RefPtr<WeakLink> m_link;
  150. };
  151. template<typename T>
  152. template<typename U>
  153. inline WeakPtr<U> Weakable<T>::make_weak_ptr() const
  154. {
  155. if constexpr (IsBaseOf<RefCountedBase, T>) {
  156. // Checking m_being_destroyed isn't sufficient when dealing with
  157. // a RefCounted type.The reference count will drop to 0 before the
  158. // destructor is invoked and revoke_weak_ptrs is called. So, try
  159. // to add a ref (which should fail if the ref count is at 0) so
  160. // that we prevent the destructor and revoke_weak_ptrs from being
  161. // triggered until we're done.
  162. if (!static_cast<const T*>(this)->try_ref())
  163. return {};
  164. } else {
  165. // For non-RefCounted types this means a weak reference can be
  166. // obtained until the ~Weakable destructor is invoked!
  167. if (m_being_destroyed.load(AK::MemoryOrder::memory_order_acquire))
  168. return {};
  169. }
  170. if (!m_link) {
  171. // There is a small chance that we create a new WeakLink and throw
  172. // it away because another thread beat us to it. But the window is
  173. // pretty small and the overhead isn't terrible.
  174. m_link.assign_if_null(adopt_ref(*new WeakLink(const_cast<T&>(static_cast<const T&>(*this)))));
  175. }
  176. WeakPtr<U> weak_ptr(m_link);
  177. if constexpr (IsBaseOf<RefCountedBase, T>) {
  178. // Now drop the reference we temporarily added
  179. if (static_cast<const T*>(this)->unref()) {
  180. // We just dropped the last reference, which should have called
  181. // revoke_weak_ptrs, which should have invalidated our weak_ptr
  182. VERIFY(!weak_ptr.strong_ref());
  183. return {};
  184. }
  185. }
  186. return weak_ptr;
  187. }
  188. template<typename T>
  189. struct Formatter<WeakPtr<T>> : Formatter<const T*> {
  190. ErrorOr<void> format(FormatBuilder& builder, WeakPtr<T> const& value)
  191. {
  192. #ifdef KERNEL
  193. auto ref = value.strong_ref();
  194. return Formatter<const T*>::format(builder, ref.ptr());
  195. #else
  196. return Formatter<const T*>::format(builder, value.ptr());
  197. #endif
  198. }
  199. };
  200. template<typename T>
  201. WeakPtr<T> try_make_weak_ptr(const T* ptr)
  202. {
  203. if (ptr) {
  204. return ptr->template make_weak_ptr<T>();
  205. }
  206. return {};
  207. }
  208. }
  209. using AK::WeakPtr;