summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2021-03-31 23:43:39 +0200
committerbunnei <bunneidev@gmail.com>2021-05-06 01:40:49 +0200
commitb8751630e20914482b6ba0b6347c5f8f668e9748 (patch)
treec24b9bb60f7df6e5950c694aba15815bc8ec04df /src/core
parentcommon: intrusive_red_black_tree: Disable static_assert that will not evaluate as constant on MSVC. (diff)
downloadyuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar.gz
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar.bz2
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar.lz
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar.xz
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.tar.zst
yuzu-b8751630e20914482b6ba0b6347c5f8f668e9748.zip
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/k_auto_object.cpp14
-rw-r--r--src/core/hle/kernel/k_auto_object.h290
3 files changed, 306 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c28abc24c..aa83b8733 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -161,6 +161,8 @@ add_library(core STATIC
hle/kernel/k_address_arbiter.h
hle/kernel/k_address_space_info.cpp
hle/kernel/k_address_space_info.h
+ hle/kernel/k_auto_object.cpp
+ hle/kernel/k_auto_object.h
hle/kernel/k_affinity_mask.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp
new file mode 100644
index 000000000..dbe237f09
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object.cpp
@@ -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
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
new file mode 100644
index 000000000..567dad204
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -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