1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <fbl/ref_counted_upgradeable.h> 8 #include <zircon/assert.h> 9 #include <zircon/compiler.h> 10 #include <zircon/types.h> 11 12 #include <atomic> 13 14 namespace fs { 15 16 // VnodeRefCounted implements a customized RefCounted object. 17 // 18 // It adds an additional method, "ResurrectRef", which allows Vnodes to be 19 // re-used after a reference count of zero has been reached. 20 template <typename T, 21 bool EnableAdoptionValidator = ZX_DEBUG_ASSERT_IMPLEMENTED> 22 class VnodeRefCounted : 23 private ::fbl::internal::RefCountedUpgradeableBase<EnableAdoptionValidator> { 24 public: VnodeRefCounted()25 constexpr VnodeRefCounted() {} ~VnodeRefCounted()26 ~VnodeRefCounted() {} 27 28 using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::AddRef; 29 using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::Release; 30 using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::Adopt; 31 using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::ref_count_debug; 32 33 // Don't use this method. See the relevant RefPtr implementation for details. 34 using ::fbl::internal::RefCountedUpgradeableBase<EnableAdoptionValidator>:: 35 AddRefMaybeInDestructor; 36 37 // VnodeRefCounted<> instances may not be copied, assigned or moved. 38 DISALLOW_COPY_ASSIGN_AND_MOVE(VnodeRefCounted); 39 40 // This method should only be called if the refcount was "zero", implying the 41 // object is currently executing fbl_recycle. In this case, the refcount 42 // is increased by one. 43 // 44 // This method may be called to prevent fbl_recycle from following the 45 // typical path of object deletion: instead of destroying the object, 46 // this function can be called to "reset" the lifecycle of the RefCounted 47 // object to the initialized state of "ref_count_ = 1", so it can 48 // continue to be utilized after there are no strong references. 49 // 50 // This function should be used EXCLUSIVELY from within fbl_recycle. 51 // If other clients (outside fbl_recycle) attempt to resurrect the Vnode 52 // concurrently with a call to Vnode::fbl_recycle, they risk going through 53 // the entire Vnode lifecycle and destroying it (with another call to 54 // Vnode::fbl_recycle) before the initial recycle execution terminates. ResurrectRef()55 void ResurrectRef() const { 56 if (EnableAdoptionValidator) { 57 int32_t old = this->ref_count_.load(std::memory_order_relaxed); 58 ZX_DEBUG_ASSERT_MSG(old == 0, "count %d(0x%08x) != 0\n", old, old); 59 } 60 this->ref_count_.store(1, std::memory_order_relaxed); 61 } 62 }; 63 64 } // namespace fs 65