Serenity Operating System
at master 87 lines 2.4 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Atomic.h> 10#include <Kernel/Arch/Processor.h> 11 12namespace Kernel { 13 14template<typename AtomicRefCountType> 15class AtomicEdgeAction { 16public: 17 template<typename FirstRefAction> 18 bool ref(FirstRefAction first_ref_action) 19 { 20 AtomicRefCountType expected = 0; 21 AtomicRefCountType desired = (1 << 1) | 1; 22 // Least significant bit indicates we're busy protecting/unprotecting 23 for (;;) { 24 if (m_atomic_ref_count.compare_exchange_strong(expected, desired, AK::memory_order_relaxed)) 25 break; 26 27 Processor::wait_check(); 28 29 expected &= ~1; 30 desired = expected + (1 << 1); 31 VERIFY(desired > expected); 32 if (expected == 0) 33 desired |= 1; 34 } 35 36 atomic_thread_fence(AK::memory_order_acquire); 37 38 if (expected == 0) { 39 first_ref_action(); 40 41 // drop the busy flag 42 m_atomic_ref_count.store(desired & ~1, AK::memory_order_release); 43 return true; 44 } 45 return false; 46 } 47 48 template<typename LastRefAction> 49 bool unref(LastRefAction last_ref_action) 50 { 51 AtomicRefCountType expected = 1 << 1; 52 AtomicRefCountType desired = (1 << 1) | 1; 53 // Least significant bit indicates we're busy protecting/unprotecting 54 for (;;) { 55 if (m_atomic_ref_count.compare_exchange_strong(expected, desired, AK::memory_order_relaxed)) 56 break; 57 58 Processor::wait_check(); 59 60 expected &= ~1; 61 VERIFY(expected != 0); // Someone should always have at least one reference 62 63 if (expected == 1 << 1) { 64 desired = (1 << 1) | 1; 65 } else { 66 desired = expected - (1 << 1); 67 VERIFY(desired < expected); 68 } 69 } 70 71 AK::atomic_thread_fence(AK::memory_order_release); 72 73 if (expected == 1 << 1) { 74 last_ref_action(); 75 76 // drop the busy flag and release reference 77 m_atomic_ref_count.store(0, AK::memory_order_release); 78 return true; 79 } 80 return false; 81 } 82 83private: 84 Atomic<AtomicRefCountType> m_atomic_ref_count { 0 }; 85}; 86 87}