blob: 27d4b52fe135e1d85c7a48846c2c970f871fe29c [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.
#ifndef SRC_STORAGE_LIB_VFS_CPP_REF_COUNTED_H_
#define SRC_STORAGE_LIB_VFS_CPP_REF_COUNTED_H_
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <atomic>
#include <fbl/ref_counted_upgradeable.h>
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:
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 constexpr (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);
}
protected:
constexpr VnodeRefCounted() = default;
~VnodeRefCounted() = default;
};
} // namespace fs
#endif // SRC_STORAGE_LIB_VFS_CPP_REF_COUNTED_H_