From 3be1a565f895d5399a6c1f6d0997dc528537fe86 Mon Sep 17 00:00:00 2001
From: Chloe Marcec <dmarcecguzman@gmail.com>
Date: Sat, 30 Jan 2021 20:40:49 +1100
Subject: [PATCH] kernel: Rewrite resource limit to be more accurate

Matches closer to hardware
---
 src/core/CMakeLists.txt                       |   5 +-
 .../hle/kernel/k_light_condition_variable.h   |  60 +++++++
 src/core/hle/kernel/k_resource_limit.cpp      | 155 ++++++++++++++++++
 src/core/hle/kernel/k_resource_limit.h        |  80 +++++++++
 src/core/hle/kernel/k_thread.cpp              |   4 +-
 src/core/hle/kernel/kernel.cpp                |  30 ++--
 src/core/hle/kernel/kernel.h                  |   4 +-
 src/core/hle/kernel/memory/page_table.cpp     |  13 +-
 src/core/hle/kernel/process.cpp               |  24 +--
 src/core/hle/kernel/process.h                 |   6 +-
 src/core/hle/kernel/resource_limit.cpp        |  73 ---------
 src/core/hle/kernel/resource_limit.h          | 106 ------------
 src/core/hle/kernel/svc.cpp                   |  28 ++--
 13 files changed, 357 insertions(+), 231 deletions(-)
 create mode 100644 src/core/hle/kernel/k_light_condition_variable.h
 create mode 100644 src/core/hle/kernel/k_resource_limit.cpp
 create mode 100644 src/core/hle/kernel/k_resource_limit.h
 delete mode 100644 src/core/hle/kernel/resource_limit.cpp
 delete mode 100644 src/core/hle/kernel/resource_limit.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 397cc028fd..0ee02c81dc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -160,9 +160,12 @@ add_library(core STATIC
     hle/kernel/k_affinity_mask.h
     hle/kernel/k_condition_variable.cpp
     hle/kernel/k_condition_variable.h
+    hle/kernel/k_light_condition_variable.h
     hle/kernel/k_light_lock.cpp
     hle/kernel/k_light_lock.h
     hle/kernel/k_priority_queue.h
+    hle/kernel/k_resource_limit.cpp
+    hle/kernel/k_resource_limit.h
     hle/kernel/k_scheduler.cpp
     hle/kernel/k_scheduler.h
     hle/kernel/k_scheduler_lock.h
@@ -203,8 +206,6 @@ add_library(core STATIC
     hle/kernel/process_capability.h
     hle/kernel/readable_event.cpp
     hle/kernel/readable_event.h
-    hle/kernel/resource_limit.cpp
-    hle/kernel/resource_limit.h
     hle/kernel/server_port.cpp
     hle/kernel/server_port.h
     hle/kernel/server_session.cpp
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
new file mode 100644
index 0000000000..26573a2397
--- /dev/null
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -0,0 +1,60 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// This file references various implementation details from Atmosphere, an open-source firmware for
+// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_thread_queue.h"
+#include "core/hle/kernel/time_manager.h"
+
+namespace Kernel {
+class KernelCore;
+
+class KLightConditionVariable {
+private:
+    KThreadQueue m_thread_queue;
+
+public:
+    KLightConditionVariable(KernelCore& kernel) : m_thread_queue(kernel), kernel(kernel) {}
+
+    void Wait(KLightLock* lock, s64 timeout = -1ll) {
+        WaitImpl(lock, timeout);
+        lock->Lock();
+    }
+
+    void Broadcast() {
+        KScopedSchedulerLock lk{kernel};
+        while (m_thread_queue.WakeupFrontThread() != nullptr) {
+            /* We want to signal all threads, and so should continue waking up until there's nothing
+             * to wake. */
+        }
+    }
+
+private:
+    void WaitImpl(KLightLock* lock, s64 timeout) {
+        KThread* owner = GetCurrentThreadPointer(kernel);
+        // KHardwareTimer* timer;
+
+        /* Sleep the thread. */
+        {
+            KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
+            lock->Unlock();
+
+            if (!m_thread_queue.SleepThread(owner)) {
+                lk.CancelSleep();
+                return;
+            }
+        }
+
+        /* Cancel the task that the sleep setup. */
+        kernel.TimeManager().UnscheduleTimeEvent(owner);
+    }
+    KernelCore& kernel;
+};
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
new file mode 100644
index 0000000000..f943d65624
--- /dev/null
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -0,0 +1,155 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// This file references various implementation details from Atmosphere, an open-source firmware for
+// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/core_timing_util.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+namespace {
+static const s64 DefaultTimeout =
+    Core::Timing::msToCycles(std::chrono::milliseconds{10000}); // 10 seconds
+}
+
+KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
+    : Object{kernel}, m_lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
+KResourceLimit::~KResourceLimit() = default;
+
+s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
+    const auto index = static_cast<std::size_t>(which);
+    s64 value{};
+    {
+        KScopedLightLock lk{m_lock};
+        value = limit_values[index];
+        ASSERT(value >= 0);
+        ASSERT(current_values[index] <= limit_values[index]);
+        ASSERT(current_hints[index] <= current_values[index]);
+    }
+    return value;
+}
+
+s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
+    const auto index = static_cast<std::size_t>(which);
+    s64 value{};
+    {
+        KScopedLightLock lk{m_lock};
+        value = current_values[index];
+        ASSERT(value >= 0);
+        ASSERT(current_values[index] <= limit_values[index]);
+        ASSERT(current_hints[index] <= current_values[index]);
+    }
+    return value;
+}
+
+s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
+    const auto index = static_cast<std::size_t>(which);
+    s64 value{};
+    {
+        KScopedLightLock lk{m_lock};
+        value = peak_values[index];
+        ASSERT(value >= 0);
+        ASSERT(current_values[index] <= limit_values[index]);
+        ASSERT(current_hints[index] <= current_values[index]);
+    }
+    return value;
+}
+
+s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
+    const auto index = static_cast<std::size_t>(which);
+    s64 value{};
+    {
+        KScopedLightLock lk(m_lock);
+        ASSERT(current_values[index] >= 0);
+        ASSERT(current_values[index] <= limit_values[index]);
+        ASSERT(current_hints[index] <= current_values[index]);
+        value = limit_values[index] - current_values[index];
+    }
+
+    return value;
+}
+
+ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
+    const auto index = static_cast<std::size_t>(which);
+    KScopedLightLock lk(m_lock);
+    R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState);
+
+    limit_values[index] = value;
+
+    return RESULT_SUCCESS;
+}
+
+bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
+    return Reserve(which, value, system.CoreTiming().GetClockTicks() + DefaultTimeout);
+}
+
+bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
+    ASSERT(value >= 0);
+    const auto index = static_cast<std::size_t>(which);
+    KScopedLightLock lk(m_lock);
+
+    ASSERT(current_hints[index] <= current_values[index]);
+    if (current_hints[index] >= limit_values[index]) {
+        return false;
+    }
+
+    /* Loop until we reserve or run out of time. */
+    while (true) {
+        ASSERT(current_values[index] <= limit_values[index]);
+        ASSERT(current_hints[index] <= current_values[index]);
+
+        /* If we would overflow, don't allow to succeed. */
+        if (current_values[index] + value <= current_values[index]) {
+            break;
+        }
+
+        if (current_values[index] + value <= limit_values[index]) {
+            current_values[index] += value;
+            current_hints[index] += value;
+            peak_values[index] = std::max(peak_values[index], current_values[index]);
+            return true;
+        }
+
+        if (current_hints[index] + value <= limit_values[index] &&
+            (timeout < 0 || system.CoreTiming().GetClockTicks() < static_cast<u64>(timeout))) {
+            waiter_count++;
+            cond_var.Wait(&m_lock, timeout);
+            waiter_count--;
+        } else {
+            break;
+        }
+    }
+
+    return false;
+}
+
+void KResourceLimit::Release(LimitableResource which, s64 value) {
+    Release(which, value, value);
+}
+
+void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
+    ASSERT(value >= 0);
+    ASSERT(hint >= 0);
+
+    const auto index = static_cast<std::size_t>(which);
+    KScopedLightLock lk(m_lock);
+    ASSERT(current_values[index] <= limit_values[index]);
+    ASSERT(current_hints[index] <= current_values[index]);
+    ASSERT(value <= current_values[index]);
+    ASSERT(hint <= current_hints[index]);
+
+    current_values[index] -= value;
+    current_hints[index] -= hint;
+
+    if (waiter_count != 0) {
+        cond_var.Broadcast();
+    }
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
new file mode 100644
index 0000000000..84c59177c0
--- /dev/null
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -0,0 +1,80 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// This file references various implementation details from Atmosphere, an open-source firmware for
+// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
+
+#pragma once
+
+#include <array>
+#include "common/common_types.h"
+#include "core/hle/kernel/k_light_condition_variable.h"
+#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/object.h"
+
+union ResultCode;
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KernelCore;
+enum class LimitableResource : u32 {
+    PhysicalMemoryMax = 0,
+    ThreadCountMax = 1,
+    EventCountMax = 2,
+    TransferMemoryCountMax = 3,
+    SessionCountMax = 4,
+
+    Count,
+};
+
+constexpr bool IsValidResourceType(LimitableResource type) {
+    return type < LimitableResource::Count;
+}
+
+class KResourceLimit final : public Object {
+public:
+    KResourceLimit(KernelCore& kernel, Core::System& system);
+    ~KResourceLimit();
+
+    s64 GetLimitValue(LimitableResource which) const;
+    s64 GetCurrentValue(LimitableResource which) const;
+    s64 GetPeakValue(LimitableResource which) const;
+    s64 GetFreeValue(LimitableResource which) const;
+
+    ResultCode SetLimitValue(LimitableResource which, s64 value);
+
+    bool Reserve(LimitableResource which, s64 value);
+    bool Reserve(LimitableResource which, s64 value, s64 timeout);
+    void Release(LimitableResource which, s64 value);
+    void Release(LimitableResource which, s64 value, s64 hint);
+
+    std::string GetTypeName() const override {
+        return "KResourceLimit";
+    }
+    std::string GetName() const override {
+        return GetTypeName();
+    }
+
+    static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
+    HandleType GetHandleType() const override {
+        return HANDLE_TYPE;
+    }
+
+    virtual void Finalize() override {}
+
+private:
+    std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> limit_values{};
+    std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_values{};
+    std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_hints{};
+    std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> peak_values{};
+    mutable KLightLock m_lock;
+    s32 waiter_count{};
+    KLightConditionVariable cond_var;
+    KernelCore& kernel;
+    Core::System& system;
+};
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index aa100e1390..38fd8e500c 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -21,6 +21,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_thread.h"
@@ -29,7 +30,6 @@
 #include "core/hle/kernel/memory/memory_layout.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/svc_results.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/result.h"
@@ -247,7 +247,7 @@ void KThread::Finalize() {
     // Decrement the parent process's thread count.
     if (parent != nullptr) {
         parent->DecrementThreadCount();
-        parent->GetResourceLimit()->Release(ResourceType::Threads, 1);
+        parent->GetResourceLimit()->Release(LimitableResource::ThreadCountMax, 1);
     }
 }
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index df309d523d..c66a993c24 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -28,6 +28,7 @@
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
@@ -36,7 +37,6 @@
 #include "core/hle/kernel/memory/slab_heap.h"
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/service_thread.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/time_manager.h"
@@ -66,7 +66,7 @@ struct KernelCore::Impl {
         is_phantom_mode_for_singlecore = false;
 
         InitializePhysicalCores();
-        InitializeSystemResourceLimit(kernel);
+        InitializeSystemResourceLimit(kernel, system);
         InitializeMemoryLayout();
         InitializePreemption(kernel);
         InitializeSchedulers();
@@ -131,19 +131,23 @@ struct KernelCore::Impl {
     }
 
     // Creates the default system resource limit
-    void InitializeSystemResourceLimit(KernelCore& kernel) {
-        system_resource_limit = ResourceLimit::Create(kernel);
+    void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
+        system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
 
         // If setting the default system values fails, then something seriously wrong has occurred.
-        ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000)
+        ASSERT(
+            system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, 0x100000000)
+                .IsSuccess());
+        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800)
+                   .IsSuccess());
+        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700)
+                   .IsSuccess());
+        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200)
+                   .IsSuccess());
+        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 900)
                    .IsSuccess());
-        ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
-        ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
-        ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
-        ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
 
-        if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) ||
-            !system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) {
+        if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, 0x60000)) {
             UNREACHABLE();
         }
     }
@@ -320,7 +324,7 @@ struct KernelCore::Impl {
     std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
     Kernel::TimeManager time_manager;
 
-    std::shared_ptr<ResourceLimit> system_resource_limit;
+    std::shared_ptr<KResourceLimit> system_resource_limit;
 
     std::shared_ptr<Core::Timing::EventType> preemption_event;
 
@@ -390,7 +394,7 @@ void KernelCore::Shutdown() {
     impl->Shutdown();
 }
 
-std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
+std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
     return impl->system_resource_limit;
 }
 
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index e7c77727bf..806a0d9868 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -38,7 +38,7 @@ class GlobalSchedulerContext;
 class HandleTable;
 class PhysicalCore;
 class Process;
-class ResourceLimit;
+class KResourceLimit;
 class KScheduler;
 class SharedMemory;
 class ServiceThread;
@@ -85,7 +85,7 @@ public:
     void Shutdown();
 
     /// Retrieves a shared pointer to the system resource limit instance.
-    std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
+    std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
 
     /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
     std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index 0808865540..d8c7d980a4 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -7,6 +7,7 @@
 #include "common/scope_exit.h"
 #include "core/core.h"
 #include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/address_space_info.h"
 #include "core/hle/kernel/memory/memory_block.h"
@@ -15,7 +16,6 @@
 #include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/memory/system_control.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/memory.h"
 
 namespace Kernel::Memory {
@@ -413,8 +413,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
     const std::size_t remaining_size{size - mapped_size};
     const std::size_t remaining_pages{remaining_size / PageSize};
 
-    if (process->GetResourceLimit() &&
-        !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) {
+    if (process->GetResourceLimit() && !process->GetResourceLimit()->Reserve(
+                                           LimitableResource::PhysicalMemoryMax, remaining_size)) {
         return ERR_RESOURCE_LIMIT_EXCEEDED;
     }
 
@@ -422,7 +422,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
     {
         auto block_guard = detail::ScopeExit([&] {
             system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
-            process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size);
+            process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax,
+                                                 remaining_size);
         });
 
         CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
@@ -474,7 +475,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
     CASCADE_CODE(UnmapMemory(addr, size));
 
     auto process{system.Kernel().CurrentProcess()};
-    process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size);
+    process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, mapped_size);
     physical_memory_usage -= mapped_size;
 
     return RESULT_SUCCESS;
@@ -783,7 +784,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
 
         auto process{system.Kernel().CurrentProcess()};
         if (process->GetResourceLimit() && delta != 0 &&
-            !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) {
+            !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, delta)) {
             return ERR_RESOURCE_LIMIT_EXCEEDED;
         }
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0edbfc4cca..6b63a32c56 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -15,6 +15,7 @@
 #include "core/file_sys/program_metadata.h"
 #include "core/hle/kernel/code_set.h"
 #include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
@@ -22,7 +23,6 @@
 #include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/memory/slab_heap.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/lock.h"
 #include "core/memory.h"
 #include "core/settings.h"
@@ -116,7 +116,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
 
     std::shared_ptr<Process> process = std::make_shared<Process>(system);
     process->name = std::move(name);
-    process->resource_limit = ResourceLimit::Create(kernel);
+    process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
     process->status = ProcessStatus::Created;
     process->program_id = 0;
     process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -132,7 +132,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
     return process;
 }
 
-std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
+std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
     return resource_limit;
 }
 
@@ -154,7 +154,7 @@ void Process::DecrementThreadCount() {
 }
 
 u64 Process::GetTotalPhysicalMemoryAvailable() const {
-    const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
+    const u64 capacity{resource_limit->GetCurrentValue(LimitableResource::PhysicalMemoryMax) +
                        page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
                        main_thread_stack_size};
 
@@ -308,13 +308,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
 
     // Set initial resource limits
     resource_limit->SetLimitValue(
-        ResourceType::PhysicalMemory,
+        LimitableResource::PhysicalMemoryMax,
         kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
-    resource_limit->SetLimitValue(ResourceType::Threads, 608);
-    resource_limit->SetLimitValue(ResourceType::Events, 700);
-    resource_limit->SetLimitValue(ResourceType::TransferMemory, 128);
-    resource_limit->SetLimitValue(ResourceType::Sessions, 894);
-    ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size));
+    resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 608);
+    resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700);
+    resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 128);
+    resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 894);
+    ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, code_size));
 
     // Create TLS region
     tls_region_address = CreateTLSRegion();
@@ -331,8 +331,8 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
     ChangeStatus(ProcessStatus::Running);
 
     SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
-    resource_limit->Reserve(ResourceType::Threads, 1);
-    resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size);
+    resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
+    resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
 }
 
 void Process::PrepareForTermination() {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 26e647743e..c8af76ce8b 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -29,7 +29,7 @@ class ProgramMetadata;
 namespace Kernel {
 
 class KernelCore;
-class ResourceLimit;
+class KResourceLimit;
 class KThread;
 class TLSPage;
 
@@ -170,7 +170,7 @@ public:
     }
 
     /// Gets the resource limit descriptor for this process
-    std::shared_ptr<ResourceLimit> GetResourceLimit() const;
+    std::shared_ptr<KResourceLimit> GetResourceLimit() const;
 
     /// Gets the ideal CPU core ID for this process
     u8 GetIdealCoreId() const {
@@ -402,7 +402,7 @@ private:
     u32 system_resource_size = 0;
 
     /// Resource limit descriptor for this process
-    std::shared_ptr<ResourceLimit> resource_limit;
+    std::shared_ptr<KResourceLimit> resource_limit;
 
     /// The ideal CPU core for this process, threads are scheduled on this core by default.
     u8 ideal_core = 0;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
deleted file mode 100644
index 7bf50339d2..0000000000
--- a/src/core/hle/kernel/resource_limit.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/resource_limit.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-namespace {
-constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
-    return static_cast<std::size_t>(type);
-}
-} // Anonymous namespace
-
-ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
-ResourceLimit::~ResourceLimit() = default;
-
-bool ResourceLimit::Reserve(ResourceType resource, s64 amount) {
-    return Reserve(resource, amount, 10000000000);
-}
-
-bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) {
-    const std::size_t index{ResourceTypeToIndex(resource)};
-
-    s64 new_value = current[index] + amount;
-    if (new_value > limit[index] && available[index] + amount <= limit[index]) {
-        // TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout
-        new_value = current[index] + amount;
-    }
-
-    if (new_value <= limit[index]) {
-        current[index] = new_value;
-        return true;
-    }
-    return false;
-}
-
-void ResourceLimit::Release(ResourceType resource, u64 amount) {
-    Release(resource, amount, amount);
-}
-
-void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) {
-    const std::size_t index{ResourceTypeToIndex(resource)};
-
-    current[index] -= used_amount;
-    available[index] -= available_amount;
-}
-
-std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
-    return std::make_shared<ResourceLimit>(kernel);
-}
-
-s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
-    return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource));
-}
-
-s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
-    return limit.at(ResourceTypeToIndex(resource));
-}
-
-ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
-    const std::size_t index{ResourceTypeToIndex(resource)};
-    if (current[index] <= value) {
-        limit[index] = value;
-        return RESULT_SUCCESS;
-    } else {
-        LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource,
-                  value, index);
-        return ERR_INVALID_STATE;
-    }
-}
-} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
deleted file mode 100644
index 464d4f2a61..0000000000
--- a/src/core/hle/kernel/resource_limit.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <array>
-#include <memory>
-
-#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
-
-union ResultCode;
-
-namespace Kernel {
-
-class KernelCore;
-
-enum class ResourceType : u32 {
-    PhysicalMemory,
-    Threads,
-    Events,
-    TransferMemory,
-    Sessions,
-
-    // Used as a count, not an actual type.
-    ResourceTypeCount
-};
-
-constexpr bool IsValidResourceType(ResourceType type) {
-    return type < ResourceType::ResourceTypeCount;
-}
-
-class ResourceLimit final : public Object {
-public:
-    explicit ResourceLimit(KernelCore& kernel);
-    ~ResourceLimit() override;
-
-    /// Creates a resource limit object.
-    static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel);
-
-    std::string GetTypeName() const override {
-        return "ResourceLimit";
-    }
-    std::string GetName() const override {
-        return GetTypeName();
-    }
-
-    static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
-    HandleType GetHandleType() const override {
-        return HANDLE_TYPE;
-    }
-
-    bool Reserve(ResourceType resource, s64 amount);
-    bool Reserve(ResourceType resource, s64 amount, u64 timeout);
-    void Release(ResourceType resource, u64 amount);
-    void Release(ResourceType resource, u64 used_amount, u64 available_amount);
-
-    /**
-     * Gets the current value for the specified resource.
-     * @param resource Requested resource type
-     * @returns The current value of the resource type
-     */
-    s64 GetCurrentResourceValue(ResourceType resource) const;
-
-    /**
-     * Gets the max value for the specified resource.
-     * @param resource Requested resource type
-     * @returns The max value of the resource type
-     */
-    s64 GetMaxResourceValue(ResourceType resource) const;
-
-    /**
-     * Sets the limit value for a given resource type.
-     *
-     * @param resource The resource type to apply the limit to.
-     * @param value    The limit to apply to the given resource type.
-     *
-     * @return A result code indicating if setting the limit value
-     *         was successful or not.
-     *
-     * @note The supplied limit value *must* be greater than or equal to
-     *       the current resource value for the given resource type,
-     *       otherwise ERR_INVALID_STATE will be returned.
-     */
-    ResultCode SetLimitValue(ResourceType resource, s64 value);
-
-    void Finalize() override {}
-
-private:
-    // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
-    // functions
-    //
-    // Currently we have no way of distinguishing if a Create was called by the running application,
-    // or by a service module. Approach this once we have separated the service modules into their
-    // own processes
-
-    using ResourceArray =
-        std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
-
-    ResourceArray limit{};
-    ResourceArray current{};
-    ResourceArray available{};
-};
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 7fd514e9d3..4bae37d105 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -26,6 +26,7 @@
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_address_arbiter.h"
 #include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_synchronization_object.h"
@@ -37,7 +38,6 @@
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/svc.h"
 #include "core/hle/kernel/svc_results.h"
@@ -141,7 +141,7 @@ enum class ResourceLimitValueType {
 ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
                                           u32 resource_type, ResourceLimitValueType value_type) {
     std::lock_guard lock{HLE::g_hle_lock};
-    const auto type = static_cast<ResourceType>(resource_type);
+    const auto type = static_cast<LimitableResource>(resource_type);
     if (!IsValidResourceType(type)) {
         LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
         return ERR_INVALID_ENUM_VALUE;
@@ -151,7 +151,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
     ASSERT(current_process != nullptr);
 
     const auto resource_limit_object =
-        current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
+        current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
     if (!resource_limit_object) {
         LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
                   resource_limit);
@@ -159,10 +159,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
     }
 
     if (value_type == ResourceLimitValueType::CurrentValue) {
-        return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
+        return MakeResult(resource_limit_object->GetCurrentValue(type));
     }
 
-    return MakeResult(resource_limit_object->GetMaxResourceValue(type));
+    return MakeResult(resource_limit_object->GetLimitValue(type));
 }
 } // Anonymous namespace
 
@@ -312,7 +312,8 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
         return ERR_NOT_FOUND;
     }
 
-    ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1));
+    ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::SessionCountMax,
+                                                                1));
 
     auto client_port = it->second;
 
@@ -1450,7 +1451,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
              Svc::ResultInvalidPriority);
     R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
 
-    ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1));
+    ASSERT(process.GetResourceLimit()->Reserve(
+        LimitableResource::ThreadCountMax, 1,
+        system.CoreTiming().GetClockTicks() +
+            Core::Timing::msToCycles(std::chrono::milliseconds{100})));
 
     std::shared_ptr<KThread> thread;
     {
@@ -1972,7 +1976,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle)
     LOG_DEBUG(Kernel_SVC, "called");
 
     auto& kernel = system.Kernel();
-    auto resource_limit = ResourceLimit::Create(kernel);
+    auto resource_limit = std::make_shared<KResourceLimit>(kernel, system);
 
     auto* const current_process = kernel.CurrentProcess();
     ASSERT(current_process != nullptr);
@@ -2019,7 +2023,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
     LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
               resource_type, value);
 
-    const auto type = static_cast<ResourceType>(resource_type);
+    const auto type = static_cast<LimitableResource>(resource_type);
     if (!IsValidResourceType(type)) {
         LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
         return ERR_INVALID_ENUM_VALUE;
@@ -2029,7 +2033,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
     ASSERT(current_process != nullptr);
 
     auto resource_limit_object =
-        current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
+        current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
     if (!resource_limit_object) {
         LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
                   resource_limit);
@@ -2041,8 +2045,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
         LOG_ERROR(
             Kernel_SVC,
             "Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
-            resource_limit_object->GetMaxResourceValue(type), resource_type,
-            resource_limit_object->GetCurrentResourceValue(type));
+            resource_limit_object->GetLimitValue(type), resource_type,
+            resource_limit_object->GetCurrentValue(type));
         return set_result;
     }