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