12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- /*
- * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/RefCounted.h>
- namespace Kernel {
- // ListedRefCounted<T> is a slot-in replacement for RefCounted<T> to use in classes
- // that add themselves to a {Spinlock, Mutex}Protected<IntrusiveList> when constructed.
- // The custom unref() implementation here ensures that the list is locked during
- // unref(), and that the T is removed from the list before ~T() is invoked.
- enum class LockType {
- Spinlock,
- Mutex,
- };
- template<typename T, LockType Lock>
- class ListedRefCounted : public RefCountedBase {
- public:
- bool unref() const
- {
- auto const* that = static_cast<T const*>(this);
- auto callback = [&](auto& list) {
- auto new_ref_count = deref_base();
- if (new_ref_count == 0) {
- list.remove(const_cast<T&>(*that));
- if constexpr (requires { that->revoke_weak_ptrs(); }) {
- that->revoke_weak_ptrs();
- }
- }
- return new_ref_count;
- };
- RefCountType new_ref_count;
- if constexpr (Lock == LockType::Spinlock)
- new_ref_count = T::all_instances().with(callback);
- else if constexpr (Lock == LockType::Mutex)
- new_ref_count = T::all_instances().with_exclusive(callback);
- if (new_ref_count == 0) {
- if constexpr (requires { that->will_be_destroyed(); })
- that->will_be_destroyed();
- delete that;
- } else if (new_ref_count == 1) {
- if constexpr (requires { that->one_ref_left(); })
- that->one_ref_left();
- }
- return new_ref_count == 0;
- }
- };
- }
|