ListedRefCounted.h 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/RefCounted.h>
  8. namespace Kernel {
  9. // ListedRefCounted<T> is a slot-in replacement for RefCounted<T> to use in classes
  10. // that add themselves to a {Spinlock, Mutex}Protected<IntrusiveList> when constructed.
  11. // The custom unref() implementation here ensures that the list is locked during
  12. // unref(), and that the T is removed from the list before ~T() is invoked.
  13. enum class LockType {
  14. Spinlock,
  15. Mutex,
  16. };
  17. template<typename T, LockType Lock>
  18. class ListedRefCounted : public RefCountedBase {
  19. public:
  20. bool unref() const
  21. {
  22. auto callback = [&](auto& list) {
  23. auto new_ref_count = deref_base();
  24. if (new_ref_count == 0)
  25. list.remove(const_cast<T&>(static_cast<T const&>(*this)));
  26. return new_ref_count;
  27. };
  28. RefCountType new_ref_count;
  29. if constexpr (Lock == LockType::Spinlock)
  30. new_ref_count = T::all_instances().with(callback);
  31. else if constexpr (Lock == LockType::Mutex)
  32. new_ref_count = T::all_instances().with_exclusive(callback);
  33. if (new_ref_count == 0) {
  34. call_will_be_destroyed_if_present(static_cast<const T*>(this));
  35. delete const_cast<T*>(static_cast<T const*>(this));
  36. } else if (new_ref_count == 1) {
  37. call_one_ref_left_if_present(static_cast<T const*>(this));
  38. }
  39. return new_ref_count == 0;
  40. }
  41. };
  42. }