Serenity Operating System
at master 88 lines 2.3 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Assertions.h> 10#include <AK/Atomic.h> 11#include <AK/Checked.h> 12#include <AK/Noncopyable.h> 13#include <AK/Platform.h> 14 15namespace AK { 16 17class AtomicRefCountedBase { 18 AK_MAKE_NONCOPYABLE(AtomicRefCountedBase); 19 AK_MAKE_NONMOVABLE(AtomicRefCountedBase); 20 21public: 22 using RefCountType = unsigned int; 23 using AllowOwnPtr = FalseType; 24 25 void ref() const 26 { 27 auto old_ref_count = m_ref_count.fetch_add(1, AK::MemoryOrder::memory_order_relaxed); 28 VERIFY(old_ref_count > 0); 29 VERIFY(!Checked<RefCountType>::addition_would_overflow(old_ref_count, 1)); 30 } 31 32 [[nodiscard]] bool try_ref() const 33 { 34 RefCountType expected = m_ref_count.load(AK::MemoryOrder::memory_order_relaxed); 35 for (;;) { 36 if (expected == 0) 37 return false; 38 VERIFY(!Checked<RefCountType>::addition_would_overflow(expected, 1)); 39 if (m_ref_count.compare_exchange_strong(expected, expected + 1, AK::MemoryOrder::memory_order_acquire)) 40 return true; 41 } 42 } 43 44 [[nodiscard]] RefCountType ref_count() const 45 { 46 return m_ref_count.load(AK::MemoryOrder::memory_order_relaxed); 47 } 48 49protected: 50 AtomicRefCountedBase() = default; 51 ~AtomicRefCountedBase() 52 { 53 VERIFY(m_ref_count.load(AK::MemoryOrder::memory_order_relaxed) == 0); 54 } 55 56 RefCountType deref_base() const 57 { 58 auto old_ref_count = m_ref_count.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel); 59 VERIFY(old_ref_count > 0); 60 return old_ref_count - 1; 61 } 62 63 mutable Atomic<RefCountType> m_ref_count { 1 }; 64}; 65 66template<typename T> 67class AtomicRefCounted : public AtomicRefCountedBase { 68public: 69 bool unref() const 70 { 71 auto* that = const_cast<T*>(static_cast<T const*>(this)); 72 auto new_ref_count = deref_base(); 73 if (new_ref_count == 0) { 74 if constexpr (requires { that->will_be_destroyed(); }) 75 that->will_be_destroyed(); 76 delete that; 77 return true; 78 } 79 return false; 80 } 81}; 82 83} 84 85#if USING_AK_GLOBALLY 86using AK::AtomicRefCounted; 87using AK::AtomicRefCountedBase; 88#endif