ThreadSafeRefCounted.h 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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/Assertions.h>
  8. #include <AK/Atomic.h>
  9. #include <AK/Checked.h>
  10. #include <AK/Noncopyable.h>
  11. #include <AK/Platform.h>
  12. #include <AK/StdLibExtras.h>
  13. namespace AK {
  14. class RefCountedBase {
  15. AK_MAKE_NONCOPYABLE(RefCountedBase);
  16. AK_MAKE_NONMOVABLE(RefCountedBase);
  17. public:
  18. using RefCountType = unsigned int;
  19. using AllowOwnPtr = FalseType;
  20. void ref() const
  21. {
  22. auto old_ref_count = m_ref_count.fetch_add(1, AK::MemoryOrder::memory_order_relaxed);
  23. VERIFY(old_ref_count > 0);
  24. VERIFY(!Checked<RefCountType>::addition_would_overflow(old_ref_count, 1));
  25. }
  26. [[nodiscard]] bool try_ref() const
  27. {
  28. RefCountType expected = m_ref_count.load(AK::MemoryOrder::memory_order_relaxed);
  29. for (;;) {
  30. if (expected == 0)
  31. return false;
  32. VERIFY(!Checked<RefCountType>::addition_would_overflow(expected, 1));
  33. if (m_ref_count.compare_exchange_strong(expected, expected + 1, AK::MemoryOrder::memory_order_acquire))
  34. return true;
  35. }
  36. }
  37. [[nodiscard]] RefCountType ref_count() const
  38. {
  39. return m_ref_count.load(AK::MemoryOrder::memory_order_relaxed);
  40. }
  41. protected:
  42. RefCountedBase() = default;
  43. ~RefCountedBase()
  44. {
  45. VERIFY(m_ref_count.load(AK::MemoryOrder::memory_order_relaxed) == 0);
  46. }
  47. RefCountType deref_base() const
  48. {
  49. auto old_ref_count = m_ref_count.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel);
  50. VERIFY(old_ref_count > 0);
  51. return old_ref_count - 1;
  52. }
  53. mutable Atomic<RefCountType> m_ref_count { 1 };
  54. };
  55. template<typename T>
  56. class RefCounted : public RefCountedBase {
  57. public:
  58. bool unref() const
  59. {
  60. auto const* that = static_cast<T const*>(this);
  61. auto new_ref_count = deref_base();
  62. if (new_ref_count == 0) {
  63. if constexpr (requires { that->will_be_destroyed(); })
  64. that->will_be_destroyed();
  65. delete that;
  66. return true;
  67. }
  68. if (new_ref_count == 1) {
  69. if constexpr (requires { that->one_ref_left(); })
  70. that->one_ref_left();
  71. }
  72. return false;
  73. }
  74. };
  75. }
  76. using AK::RefCounted;
  77. using AK::RefCountedBase;