3 changed files with 306 additions and 0 deletions
-
2src/core/CMakeLists.txt
-
14src/core/hle/kernel/k_auto_object.cpp
-
290src/core/hle/kernel/k_auto_object.h
@ -0,0 +1,14 @@ |
|||
// Copyright 2021 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "core/hle/kernel/k_auto_object.h"
|
|||
|
|||
namespace Kernel { |
|||
|
|||
KAutoObject* KAutoObject::Create(KAutoObject* obj) { |
|||
obj->m_ref_count = 1; |
|||
return obj; |
|||
} |
|||
|
|||
} // namespace Kernel
|
|||
@ -0,0 +1,290 @@ |
|||
// Copyright 2021 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
|
|||
#include "common/assert.h" |
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
#include "common/intrusive_red_black_tree.h" |
|||
#include "core/hle/kernel/k_class_token.h" |
|||
|
|||
namespace Kernel { |
|||
|
|||
class Process; |
|||
|
|||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ |
|||
NON_COPYABLE(CLASS); \ |
|||
NON_MOVEABLE(CLASS); \ |
|||
\ |
|||
private: \ |
|||
friend class ::Kernel::KClassTokenGenerator; \ |
|||
static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \ |
|||
static constexpr inline const char* const TypeName = #CLASS; \ |
|||
static constexpr inline ClassTokenType ClassToken() { \ |
|||
return ::Kernel::ClassToken<CLASS>; \ |
|||
} \ |
|||
\ |
|||
public: \ |
|||
using BaseClass = BASE_CLASS; \ |
|||
static constexpr TypeObj GetStaticTypeObj() { \ |
|||
constexpr ClassTokenType Token = ClassToken(); \ |
|||
return TypeObj(TypeName, Token); \ |
|||
} \ |
|||
static constexpr const char* GetStaticTypeName() { \ |
|||
return TypeName; \ |
|||
} \ |
|||
virtual TypeObj GetTypeObj() const { \ |
|||
return GetStaticTypeObj(); \ |
|||
} \ |
|||
virtual const char* GetTypeName() { \ |
|||
return GetStaticTypeName(); \ |
|||
} \ |
|||
\ |
|||
private: |
|||
|
|||
class KAutoObject { |
|||
protected: |
|||
class TypeObj { |
|||
private: |
|||
const char* m_name; |
|||
ClassTokenType m_class_token; |
|||
|
|||
public: |
|||
constexpr explicit TypeObj(const char* n, ClassTokenType tok) |
|||
: m_name(n), m_class_token(tok) { // ... |
|||
} |
|||
|
|||
constexpr const char* GetName() const { |
|||
return m_name; |
|||
} |
|||
constexpr ClassTokenType GetClassToken() const { |
|||
return m_class_token; |
|||
} |
|||
|
|||
constexpr bool operator==(const TypeObj& rhs) { |
|||
return this->GetClassToken() == rhs.GetClassToken(); |
|||
} |
|||
|
|||
constexpr bool operator!=(const TypeObj& rhs) { |
|||
return this->GetClassToken() != rhs.GetClassToken(); |
|||
} |
|||
|
|||
constexpr bool IsDerivedFrom(const TypeObj& rhs) { |
|||
return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken(); |
|||
} |
|||
}; |
|||
|
|||
private: |
|||
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); |
|||
|
|||
private: |
|||
std::atomic<u32> m_ref_count; |
|||
|
|||
public: |
|||
static KAutoObject* Create(KAutoObject* ptr); |
|||
|
|||
public: |
|||
constexpr explicit KAutoObject() : m_ref_count(0) {} |
|||
virtual ~KAutoObject() {} |
|||
|
|||
// Destroy is responsible for destroying the auto object's resources when ref_count hits zero. |
|||
virtual void Destroy() { |
|||
UNIMPLEMENTED(); |
|||
} |
|||
|
|||
// Finalize is responsible for cleaning up resource, but does not destroy the object. |
|||
virtual void Finalize() { |
|||
UNIMPLEMENTED(); |
|||
} |
|||
|
|||
virtual Process* GetOwner() const { |
|||
return nullptr; |
|||
} |
|||
|
|||
u32 GetReferenceCount() const { |
|||
return m_ref_count.load(); |
|||
} |
|||
|
|||
bool IsDerivedFrom(const TypeObj& rhs) const { |
|||
return this->GetTypeObj().IsDerivedFrom(rhs); |
|||
} |
|||
|
|||
bool IsDerivedFrom(const KAutoObject& rhs) const { |
|||
return this->IsDerivedFrom(rhs.GetTypeObj()); |
|||
} |
|||
|
|||
template <typename Derived> |
|||
Derived DynamicCast() { |
|||
static_assert(std::is_pointer<Derived>::value); |
|||
using DerivedType = typename std::remove_pointer<Derived>::type; |
|||
|
|||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { |
|||
return static_cast<Derived>(this); |
|||
} else { |
|||
return nullptr; |
|||
} |
|||
} |
|||
|
|||
template <typename Derived> |
|||
const Derived DynamicCast() const { |
|||
static_assert(std::is_pointer<Derived>::value); |
|||
using DerivedType = typename std::remove_pointer<Derived>::type; |
|||
|
|||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { |
|||
return static_cast<Derived>(this); |
|||
} else { |
|||
return nullptr; |
|||
} |
|||
} |
|||
|
|||
bool Open() { |
|||
// Atomically increment the reference count, only if it's positive. |
|||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); |
|||
do { |
|||
if (cur_ref_count == 0) { |
|||
return false; |
|||
} |
|||
ASSERT(cur_ref_count < cur_ref_count + 1); |
|||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1, |
|||
std::memory_order_relaxed)); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void Close() { |
|||
// Atomically decrement the reference count, not allowing it to become negative. |
|||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); |
|||
do { |
|||
ASSERT(cur_ref_count > 0); |
|||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, |
|||
std::memory_order_relaxed)); |
|||
|
|||
// If ref count hits zero, destroy the object. |
|||
if (cur_ref_count - 1 == 0) { |
|||
this->Destroy(); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
class KAutoObjectWithListContainer; |
|||
|
|||
class KAutoObjectWithList : public KAutoObject { |
|||
private: |
|||
friend class KAutoObjectWithListContainer; |
|||
|
|||
private: |
|||
Common::IntrusiveRedBlackTreeNode list_node; |
|||
|
|||
public: |
|||
static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { |
|||
const u64 lid = lhs.GetId(); |
|||
const u64 rid = rhs.GetId(); |
|||
|
|||
if (lid < rid) { |
|||
return -1; |
|||
} else if (lid > rid) { |
|||
return 1; |
|||
} else { |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
public: |
|||
virtual u64 GetId() const { |
|||
return reinterpret_cast<u64>(this); |
|||
} |
|||
}; |
|||
|
|||
template <typename T> |
|||
class KScopedAutoObject { |
|||
NON_COPYABLE(KScopedAutoObject); |
|||
|
|||
private: |
|||
template <typename U> |
|||
friend class KScopedAutoObject; |
|||
|
|||
private: |
|||
T* m_obj; |
|||
|
|||
private: |
|||
constexpr void Swap(KScopedAutoObject& rhs) { |
|||
std::swap(m_obj, rhs.m_obj); |
|||
} |
|||
|
|||
public: |
|||
constexpr KScopedAutoObject() : m_obj(nullptr) { // ... |
|||
} |
|||
constexpr KScopedAutoObject(T* o) : m_obj(o) { |
|||
if (m_obj != nullptr) { |
|||
m_obj->Open(); |
|||
} |
|||
} |
|||
|
|||
~KScopedAutoObject() { |
|||
if (m_obj != nullptr) { |
|||
m_obj->Close(); |
|||
} |
|||
m_obj = nullptr; |
|||
} |
|||
|
|||
template <typename U> |
|||
requires(std::derived_from<T, U> || |
|||
std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) { |
|||
if constexpr (std::derived_from<U, T>) { |
|||
// Upcast. |
|||
m_obj = rhs.m_obj; |
|||
rhs.m_obj = nullptr; |
|||
} else { |
|||
// Downcast. |
|||
T* derived = nullptr; |
|||
if (rhs.m_obj != nullptr) { |
|||
derived = rhs.m_obj->template DynamicCast<T*>(); |
|||
if (derived == nullptr) { |
|||
rhs.m_obj->Close(); |
|||
} |
|||
} |
|||
|
|||
m_obj = derived; |
|||
rhs.m_obj = nullptr; |
|||
} |
|||
} |
|||
|
|||
constexpr KScopedAutoObject<T>& operator=(KScopedAutoObject<T>&& rhs) { |
|||
rhs.Swap(*this); |
|||
return *this; |
|||
} |
|||
|
|||
constexpr T* operator->() { |
|||
return m_obj; |
|||
} |
|||
constexpr T& operator*() { |
|||
return *m_obj; |
|||
} |
|||
|
|||
constexpr void Reset(T* o) { |
|||
KScopedAutoObject(o).Swap(*this); |
|||
} |
|||
|
|||
constexpr T* GetPointerUnsafe() { |
|||
return m_obj; |
|||
} |
|||
|
|||
constexpr T* ReleasePointerUnsafe() { |
|||
T* ret = m_obj; |
|||
m_obj = nullptr; |
|||
return ret; |
|||
} |
|||
|
|||
constexpr bool IsNull() const { |
|||
return m_obj == nullptr; |
|||
} |
|||
constexpr bool IsNotNull() const { |
|||
return m_obj != nullptr; |
|||
} |
|||
}; |
|||
|
|||
} // namespace Kernel |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue