blob: 39444f77563d3ae94ebf0b9342428d2718171802 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <fbl/atomic.h>
#include <fbl/ref_counted_internal.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
namespace fs {
// VnodeRefCounted implements a customized RefCounted object.
//
// This object acts nearly identically to the base "RefCounted" --
// all methods have the same implementation -- but it adds an additional
// method, "ResurrectRef", which allows Vnodes to be re-used
// after a reference count of zero has been reached.
template <typename T,
bool EnableAdoptionValidator = ZX_DEBUG_ASSERT_IMPLEMENTED>
class VnodeRefCounted {
public:
constexpr VnodeRefCounted()
: ref_count_(1) {}
~VnodeRefCounted() {}
// Default methods.
void AddRef() const {
fbl::internal::AddRefDefault<EnableAdoptionValidator>(ref_count_,
adoption_validator_);
}
bool AddRefMaybeInDestructor() {
return fbl::internal::AddRefMaybeInDestructorDefault(ref_count_);
}
bool Release() const __WARN_UNUSED_RESULT {
return fbl::internal::ReleaseRefDefault<EnableAdoptionValidator>(ref_count_,
adoption_validator_);
}
void Adopt() const {
adoption_validator_.Adopt();
}
// This method should only be called if the refcount was "zero", implying the
// object is currently executing fbl_recycle. In this case, the refcount
// is increased by one.
//
// This method may be called to prevent fbl_recycle from following the
// typical path of object deletion: instead of destroying the object,
// this function can be called to "reset" the lifecycle of the RefCounted
// object to the initialized state of "ref_count_ = 1", so it can
// continue to be utilized after there are no strong references.
//
// This function should be used EXCLUSIVELY from within fbl_recycle.
// If other clients (outside fbl_recycle) attempt to resurrect the Vnode
// concurrently with a call to Vnode::fbl_recycle, they risk going through
// the entire Vnode lifecycle and destroying it (with another call to
// Vnode::fbl_recycle) before the initial recycle execution terminates.
void ResurrectRef() const {
adoption_validator_.ValidateAddRef();
if (EnableAdoptionValidator) {
int old = ref_count_.load(fbl::memory_order_acquire);
ZX_DEBUG_ASSERT_MSG(old == 0, "count %d != 0\n", old);
}
ref_count_.store(1, fbl::memory_order_release);
}
private:
mutable fbl::atomic_int ref_count_;
fbl::internal::AdoptionValidator<EnableAdoptionValidator> adoption_validator_;
// VnodeRefCounted<> instances may not be copied, assigned or moved.
DISALLOW_COPY_ASSIGN_AND_MOVE(VnodeRefCounted);
};
} // namespace fs