blob: 1c90c2463ff2caf6631c97f6459568f62f67eee9 [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/ref_counted_upgradeable.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <atomic>
namespace fs {
// VnodeRefCounted implements a customized RefCounted object.
//
// 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 :
private ::fbl::internal::RefCountedUpgradeableBase<EnableAdoptionValidator> {
public:
constexpr VnodeRefCounted() {}
~VnodeRefCounted() {}
using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::AddRef;
using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::Release;
using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::Adopt;
using ::fbl::internal::RefCountedBase<EnableAdoptionValidator>::ref_count_debug;
// Don't use this method. See the relevant RefPtr implementation for details.
using ::fbl::internal::RefCountedUpgradeableBase<EnableAdoptionValidator>::
AddRefMaybeInDestructor;
// VnodeRefCounted<> instances may not be copied, assigned or moved.
DISALLOW_COPY_ASSIGN_AND_MOVE(VnodeRefCounted);
// 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 {
if (EnableAdoptionValidator) {
int32_t old = this->ref_count_.load(std::memory_order_relaxed);
ZX_DEBUG_ASSERT_MSG(old == 0, "count %d(0x%08x) != 0\n", old, old);
}
this->ref_count_.store(1, std::memory_order_relaxed);
}
};
} // namespace fs