summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChloe Marcec <dmarcecguzman@gmail.com>2021-01-30 10:40:49 +0100
committerChloe Marcec <dmarcecguzman@gmail.com>2021-01-30 10:40:49 +0100
commit3be1a565f895d5399a6c1f6d0997dc528537fe86 (patch)
treed5c94d86c78bdcf7a73785b9c28b0c1f5fc0c6af
parentMerge pull request #5779 from bunnei/kthread-rewrite (diff)
downloadyuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar.gz
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar.bz2
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar.lz
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar.xz
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.tar.zst
yuzu-3be1a565f895d5399a6c1f6d0997dc528537fe86.zip
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h60
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp155
-rw-r--r--src/core/hle/kernel/k_resource_limit.h80
-rw-r--r--src/core/hle/kernel/k_thread.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp13
-rw-r--r--src/core/hle/kernel/process.cpp24
-rw-r--r--src/core/hle/kernel/process.h6
-rw-r--r--src/core/hle/kernel/resource_limit.cpp73
-rw-r--r--src/core/hle/kernel/resource_limit.h106
-rw-r--r--src/core/hle/kernel/svc.cpp28
13 files changed, 357 insertions, 231 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 397cc028f..0ee02c81d 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 000000000..26573a239
--- /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 000000000..f943d6562
--- /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 000000000..84c59177c
--- /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 aa100e139..38fd8e500 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 df309d523..c66a993c2 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 e7c77727b..806a0d986 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 080886554..d8c7d980a 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 0edbfc4cc..6b63a32c5 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 26e647743..c8af76ce8 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 7bf50339d..000000000
--- 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 464d4f2a6..000000000
--- 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 7fd514e9d..4bae37d10 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;
}