Serenity Operating System
at master 124 lines 3.4 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/AtomicRefCounted.h> 12#include <AK/StdLibExtras.h> 13#include <Kernel/Arch/Processor.h> 14#include <Kernel/Library/LockRefPtr.h> 15#include <Kernel/ScopedCritical.h> 16 17namespace AK { 18 19template<typename T> 20class LockWeakable; 21template<typename T> 22class LockWeakPtr; 23 24class LockWeakLink final : public AtomicRefCounted<LockWeakLink> { 25 template<typename T> 26 friend class LockWeakable; 27 template<typename T> 28 friend class LockWeakPtr; 29 30public: 31 template<typename T, typename PtrTraits = LockRefPtrTraits<T>> 32 LockRefPtr<T, PtrTraits> strong_ref() const 33 requires(IsBaseOf<AtomicRefCountedBase, T>) 34 { 35 LockRefPtr<T, PtrTraits> ref; 36 37 { 38 // We don't want to be preempted while we are trying to obtain 39 // a strong reference 40 Kernel::ScopedCritical critical; 41 if (!(m_consumers.fetch_add(1u << 1, AK::MemoryOrder::memory_order_acquire) & 1u)) { 42 T* ptr = (T*)m_ptr.load(AK::MemoryOrder::memory_order_acquire); 43 if (ptr && ptr->try_ref()) 44 ref = adopt_lock_ref(*ptr); 45 } 46 m_consumers.fetch_sub(1u << 1, AK::MemoryOrder::memory_order_release); 47 } 48 49 return ref; 50 } 51 52 template<typename T> 53 T* unsafe_ptr() const 54 { 55 if (m_consumers.load(AK::MemoryOrder::memory_order_relaxed) & 1u) 56 return nullptr; 57 // NOTE: This may return a non-null pointer even if revocation 58 // has been triggered as there is a possible race! But it's "unsafe" 59 // anyway because we return a raw pointer without ensuring a 60 // reference... 61 return (T*)m_ptr.load(AK::MemoryOrder::memory_order_acquire); 62 } 63 64 bool is_null() const 65 { 66 return unsafe_ptr<void>() == nullptr; 67 } 68 69 void revoke() 70 { 71 auto current_consumers = m_consumers.fetch_or(1u, AK::MemoryOrder::memory_order_relaxed); 72 VERIFY(!(current_consumers & 1u)); 73 // We flagged revocation, now wait until everyone trying to obtain 74 // a strong reference is done 75 while (current_consumers > 0) { 76 Kernel::Processor::wait_check(); 77 current_consumers = m_consumers.load(AK::MemoryOrder::memory_order_acquire) & ~1u; 78 } 79 // No one is trying to use it (anymore) 80 m_ptr.store(nullptr, AK::MemoryOrder::memory_order_release); 81 } 82 83private: 84 template<typename T> 85 explicit LockWeakLink(T& weakable) 86 : m_ptr(&weakable) 87 { 88 } 89 mutable Atomic<void*> m_ptr; 90 mutable Atomic<unsigned> m_consumers; // LSB indicates revocation in progress 91}; 92 93template<typename T> 94class LockWeakable { 95private: 96 class Link; 97 98public: 99 template<typename U = T> 100 ErrorOr<LockWeakPtr<U>> try_make_weak_ptr() const; 101 102protected: 103 LockWeakable() = default; 104 105 ~LockWeakable() 106 { 107 m_being_destroyed.store(true, AK::MemoryOrder::memory_order_release); 108 revoke_weak_ptrs(); 109 } 110 111 void revoke_weak_ptrs() 112 { 113 if (auto link = move(m_link)) 114 link->revoke(); 115 } 116 117private: 118 mutable LockRefPtr<LockWeakLink> m_link; 119 Atomic<bool> m_being_destroyed { false }; 120}; 121 122} 123 124using AK::LockWeakable;