diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_condition_variable.h | 60 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_resource_limit.cpp | 155 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_resource_limit.h | 80 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 24 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/resource_limit.cpp | 73 | ||||
| -rw-r--r-- | src/core/hle/kernel/resource_limit.h | 106 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 28 |
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 | |||
| 160 | hle/kernel/k_affinity_mask.h | 160 | hle/kernel/k_affinity_mask.h |
| 161 | hle/kernel/k_condition_variable.cpp | 161 | hle/kernel/k_condition_variable.cpp |
| 162 | hle/kernel/k_condition_variable.h | 162 | hle/kernel/k_condition_variable.h |
| 163 | hle/kernel/k_light_condition_variable.h | ||
| 163 | hle/kernel/k_light_lock.cpp | 164 | hle/kernel/k_light_lock.cpp |
| 164 | hle/kernel/k_light_lock.h | 165 | hle/kernel/k_light_lock.h |
| 165 | hle/kernel/k_priority_queue.h | 166 | hle/kernel/k_priority_queue.h |
| 167 | hle/kernel/k_resource_limit.cpp | ||
| 168 | hle/kernel/k_resource_limit.h | ||
| 166 | hle/kernel/k_scheduler.cpp | 169 | hle/kernel/k_scheduler.cpp |
| 167 | hle/kernel/k_scheduler.h | 170 | hle/kernel/k_scheduler.h |
| 168 | hle/kernel/k_scheduler_lock.h | 171 | hle/kernel/k_scheduler_lock.h |
| @@ -203,8 +206,6 @@ add_library(core STATIC | |||
| 203 | hle/kernel/process_capability.h | 206 | hle/kernel/process_capability.h |
| 204 | hle/kernel/readable_event.cpp | 207 | hle/kernel/readable_event.cpp |
| 205 | hle/kernel/readable_event.h | 208 | hle/kernel/readable_event.h |
| 206 | hle/kernel/resource_limit.cpp | ||
| 207 | hle/kernel/resource_limit.h | ||
| 208 | hle/kernel/server_port.cpp | 209 | hle/kernel/server_port.cpp |
| 209 | hle/kernel/server_port.h | 210 | hle/kernel/server_port.h |
| 210 | hle/kernel/server_session.cpp | 211 | 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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/k_scheduler.h" | ||
| 12 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 13 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 14 | #include "core/hle/kernel/time_manager.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | class KernelCore; | ||
| 18 | |||
| 19 | class KLightConditionVariable { | ||
| 20 | private: | ||
| 21 | KThreadQueue m_thread_queue; | ||
| 22 | |||
| 23 | public: | ||
| 24 | KLightConditionVariable(KernelCore& kernel) : m_thread_queue(kernel), kernel(kernel) {} | ||
| 25 | |||
| 26 | void Wait(KLightLock* lock, s64 timeout = -1ll) { | ||
| 27 | WaitImpl(lock, timeout); | ||
| 28 | lock->Lock(); | ||
| 29 | } | ||
| 30 | |||
| 31 | void Broadcast() { | ||
| 32 | KScopedSchedulerLock lk{kernel}; | ||
| 33 | while (m_thread_queue.WakeupFrontThread() != nullptr) { | ||
| 34 | /* We want to signal all threads, and so should continue waking up until there's nothing | ||
| 35 | * to wake. */ | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | private: | ||
| 40 | void WaitImpl(KLightLock* lock, s64 timeout) { | ||
| 41 | KThread* owner = GetCurrentThreadPointer(kernel); | ||
| 42 | // KHardwareTimer* timer; | ||
| 43 | |||
| 44 | /* Sleep the thread. */ | ||
| 45 | { | ||
| 46 | KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); | ||
| 47 | lock->Unlock(); | ||
| 48 | |||
| 49 | if (!m_thread_queue.SleepThread(owner)) { | ||
| 50 | lk.CancelSleep(); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Cancel the task that the sleep setup. */ | ||
| 56 | kernel.TimeManager().UnscheduleTimeEvent(owner); | ||
| 57 | } | ||
| 58 | KernelCore& kernel; | ||
| 59 | }; | ||
| 60 | } // 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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | ||
| 11 | #include "core/core_timing_util.h" | ||
| 12 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 13 | #include "core/hle/kernel/svc_results.h" | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | namespace { | ||
| 17 | static const s64 DefaultTimeout = | ||
| 18 | Core::Timing::msToCycles(std::chrono::milliseconds{10000}); // 10 seconds | ||
| 19 | } | ||
| 20 | |||
| 21 | KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) | ||
| 22 | : Object{kernel}, m_lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} | ||
| 23 | KResourceLimit::~KResourceLimit() = default; | ||
| 24 | |||
| 25 | s64 KResourceLimit::GetLimitValue(LimitableResource which) const { | ||
| 26 | const auto index = static_cast<std::size_t>(which); | ||
| 27 | s64 value{}; | ||
| 28 | { | ||
| 29 | KScopedLightLock lk{m_lock}; | ||
| 30 | value = limit_values[index]; | ||
| 31 | ASSERT(value >= 0); | ||
| 32 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 33 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 34 | } | ||
| 35 | return value; | ||
| 36 | } | ||
| 37 | |||
| 38 | s64 KResourceLimit::GetCurrentValue(LimitableResource which) const { | ||
| 39 | const auto index = static_cast<std::size_t>(which); | ||
| 40 | s64 value{}; | ||
| 41 | { | ||
| 42 | KScopedLightLock lk{m_lock}; | ||
| 43 | value = current_values[index]; | ||
| 44 | ASSERT(value >= 0); | ||
| 45 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 46 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 47 | } | ||
| 48 | return value; | ||
| 49 | } | ||
| 50 | |||
| 51 | s64 KResourceLimit::GetPeakValue(LimitableResource which) const { | ||
| 52 | const auto index = static_cast<std::size_t>(which); | ||
| 53 | s64 value{}; | ||
| 54 | { | ||
| 55 | KScopedLightLock lk{m_lock}; | ||
| 56 | value = peak_values[index]; | ||
| 57 | ASSERT(value >= 0); | ||
| 58 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 59 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 60 | } | ||
| 61 | return value; | ||
| 62 | } | ||
| 63 | |||
| 64 | s64 KResourceLimit::GetFreeValue(LimitableResource which) const { | ||
| 65 | const auto index = static_cast<std::size_t>(which); | ||
| 66 | s64 value{}; | ||
| 67 | { | ||
| 68 | KScopedLightLock lk(m_lock); | ||
| 69 | ASSERT(current_values[index] >= 0); | ||
| 70 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 71 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 72 | value = limit_values[index] - current_values[index]; | ||
| 73 | } | ||
| 74 | |||
| 75 | return value; | ||
| 76 | } | ||
| 77 | |||
| 78 | ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { | ||
| 79 | const auto index = static_cast<std::size_t>(which); | ||
| 80 | KScopedLightLock lk(m_lock); | ||
| 81 | R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState); | ||
| 82 | |||
| 83 | limit_values[index] = value; | ||
| 84 | |||
| 85 | return RESULT_SUCCESS; | ||
| 86 | } | ||
| 87 | |||
| 88 | bool KResourceLimit::Reserve(LimitableResource which, s64 value) { | ||
| 89 | return Reserve(which, value, system.CoreTiming().GetClockTicks() + DefaultTimeout); | ||
| 90 | } | ||
| 91 | |||
| 92 | bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { | ||
| 93 | ASSERT(value >= 0); | ||
| 94 | const auto index = static_cast<std::size_t>(which); | ||
| 95 | KScopedLightLock lk(m_lock); | ||
| 96 | |||
| 97 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 98 | if (current_hints[index] >= limit_values[index]) { | ||
| 99 | return false; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Loop until we reserve or run out of time. */ | ||
| 103 | while (true) { | ||
| 104 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 105 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 106 | |||
| 107 | /* If we would overflow, don't allow to succeed. */ | ||
| 108 | if (current_values[index] + value <= current_values[index]) { | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (current_values[index] + value <= limit_values[index]) { | ||
| 113 | current_values[index] += value; | ||
| 114 | current_hints[index] += value; | ||
| 115 | peak_values[index] = std::max(peak_values[index], current_values[index]); | ||
| 116 | return true; | ||
| 117 | } | ||
| 118 | |||
| 119 | if (current_hints[index] + value <= limit_values[index] && | ||
| 120 | (timeout < 0 || system.CoreTiming().GetClockTicks() < static_cast<u64>(timeout))) { | ||
| 121 | waiter_count++; | ||
| 122 | cond_var.Wait(&m_lock, timeout); | ||
| 123 | waiter_count--; | ||
| 124 | } else { | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | return false; | ||
| 130 | } | ||
| 131 | |||
| 132 | void KResourceLimit::Release(LimitableResource which, s64 value) { | ||
| 133 | Release(which, value, value); | ||
| 134 | } | ||
| 135 | |||
| 136 | void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) { | ||
| 137 | ASSERT(value >= 0); | ||
| 138 | ASSERT(hint >= 0); | ||
| 139 | |||
| 140 | const auto index = static_cast<std::size_t>(which); | ||
| 141 | KScopedLightLock lk(m_lock); | ||
| 142 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 143 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 144 | ASSERT(value <= current_values[index]); | ||
| 145 | ASSERT(hint <= current_hints[index]); | ||
| 146 | |||
| 147 | current_values[index] -= value; | ||
| 148 | current_hints[index] -= hint; | ||
| 149 | |||
| 150 | if (waiter_count != 0) { | ||
| 151 | cond_var.Broadcast(); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | } // 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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include <array> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/hle/kernel/k_light_condition_variable.h" | ||
| 13 | #include "core/hle/kernel/k_light_lock.h" | ||
| 14 | #include "core/hle/kernel/object.h" | ||
| 15 | |||
| 16 | union ResultCode; | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | class System; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Kernel { | ||
| 23 | class KernelCore; | ||
| 24 | enum class LimitableResource : u32 { | ||
| 25 | PhysicalMemoryMax = 0, | ||
| 26 | ThreadCountMax = 1, | ||
| 27 | EventCountMax = 2, | ||
| 28 | TransferMemoryCountMax = 3, | ||
| 29 | SessionCountMax = 4, | ||
| 30 | |||
| 31 | Count, | ||
| 32 | }; | ||
| 33 | |||
| 34 | constexpr bool IsValidResourceType(LimitableResource type) { | ||
| 35 | return type < LimitableResource::Count; | ||
| 36 | } | ||
| 37 | |||
| 38 | class KResourceLimit final : public Object { | ||
| 39 | public: | ||
| 40 | KResourceLimit(KernelCore& kernel, Core::System& system); | ||
| 41 | ~KResourceLimit(); | ||
| 42 | |||
| 43 | s64 GetLimitValue(LimitableResource which) const; | ||
| 44 | s64 GetCurrentValue(LimitableResource which) const; | ||
| 45 | s64 GetPeakValue(LimitableResource which) const; | ||
| 46 | s64 GetFreeValue(LimitableResource which) const; | ||
| 47 | |||
| 48 | ResultCode SetLimitValue(LimitableResource which, s64 value); | ||
| 49 | |||
| 50 | bool Reserve(LimitableResource which, s64 value); | ||
| 51 | bool Reserve(LimitableResource which, s64 value, s64 timeout); | ||
| 52 | void Release(LimitableResource which, s64 value); | ||
| 53 | void Release(LimitableResource which, s64 value, s64 hint); | ||
| 54 | |||
| 55 | std::string GetTypeName() const override { | ||
| 56 | return "KResourceLimit"; | ||
| 57 | } | ||
| 58 | std::string GetName() const override { | ||
| 59 | return GetTypeName(); | ||
| 60 | } | ||
| 61 | |||
| 62 | static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; | ||
| 63 | HandleType GetHandleType() const override { | ||
| 64 | return HANDLE_TYPE; | ||
| 65 | } | ||
| 66 | |||
| 67 | virtual void Finalize() override {} | ||
| 68 | |||
| 69 | private: | ||
| 70 | std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> limit_values{}; | ||
| 71 | std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_values{}; | ||
| 72 | std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_hints{}; | ||
| 73 | std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> peak_values{}; | ||
| 74 | mutable KLightLock m_lock; | ||
| 75 | s32 waiter_count{}; | ||
| 76 | KLightConditionVariable cond_var; | ||
| 77 | KernelCore& kernel; | ||
| 78 | Core::System& system; | ||
| 79 | }; | ||
| 80 | } // 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 @@ | |||
| 21 | #include "core/hle/kernel/errors.h" | 21 | #include "core/hle/kernel/errors.h" |
| 22 | #include "core/hle/kernel/handle_table.h" | 22 | #include "core/hle/kernel/handle_table.h" |
| 23 | #include "core/hle/kernel/k_condition_variable.h" | 23 | #include "core/hle/kernel/k_condition_variable.h" |
| 24 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 24 | #include "core/hle/kernel/k_scheduler.h" | 25 | #include "core/hle/kernel/k_scheduler.h" |
| 25 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 26 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 26 | #include "core/hle/kernel/k_thread.h" | 27 | #include "core/hle/kernel/k_thread.h" |
| @@ -29,7 +30,6 @@ | |||
| 29 | #include "core/hle/kernel/memory/memory_layout.h" | 30 | #include "core/hle/kernel/memory/memory_layout.h" |
| 30 | #include "core/hle/kernel/object.h" | 31 | #include "core/hle/kernel/object.h" |
| 31 | #include "core/hle/kernel/process.h" | 32 | #include "core/hle/kernel/process.h" |
| 32 | #include "core/hle/kernel/resource_limit.h" | ||
| 33 | #include "core/hle/kernel/svc_results.h" | 33 | #include "core/hle/kernel/svc_results.h" |
| 34 | #include "core/hle/kernel/time_manager.h" | 34 | #include "core/hle/kernel/time_manager.h" |
| 35 | #include "core/hle/result.h" | 35 | #include "core/hle/result.h" |
| @@ -247,7 +247,7 @@ void KThread::Finalize() { | |||
| 247 | // Decrement the parent process's thread count. | 247 | // Decrement the parent process's thread count. |
| 248 | if (parent != nullptr) { | 248 | if (parent != nullptr) { |
| 249 | parent->DecrementThreadCount(); | 249 | parent->DecrementThreadCount(); |
| 250 | parent->GetResourceLimit()->Release(ResourceType::Threads, 1); | 250 | parent->GetResourceLimit()->Release(LimitableResource::ThreadCountMax, 1); |
| 251 | } | 251 | } |
| 252 | } | 252 | } |
| 253 | 253 | ||
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 @@ | |||
| 28 | #include "core/hle/kernel/client_port.h" | 28 | #include "core/hle/kernel/client_port.h" |
| 29 | #include "core/hle/kernel/errors.h" | 29 | #include "core/hle/kernel/errors.h" |
| 30 | #include "core/hle/kernel/handle_table.h" | 30 | #include "core/hle/kernel/handle_table.h" |
| 31 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 31 | #include "core/hle/kernel/k_scheduler.h" | 32 | #include "core/hle/kernel/k_scheduler.h" |
| 32 | #include "core/hle/kernel/k_thread.h" | 33 | #include "core/hle/kernel/k_thread.h" |
| 33 | #include "core/hle/kernel/kernel.h" | 34 | #include "core/hle/kernel/kernel.h" |
| @@ -36,7 +37,6 @@ | |||
| 36 | #include "core/hle/kernel/memory/slab_heap.h" | 37 | #include "core/hle/kernel/memory/slab_heap.h" |
| 37 | #include "core/hle/kernel/physical_core.h" | 38 | #include "core/hle/kernel/physical_core.h" |
| 38 | #include "core/hle/kernel/process.h" | 39 | #include "core/hle/kernel/process.h" |
| 39 | #include "core/hle/kernel/resource_limit.h" | ||
| 40 | #include "core/hle/kernel/service_thread.h" | 40 | #include "core/hle/kernel/service_thread.h" |
| 41 | #include "core/hle/kernel/shared_memory.h" | 41 | #include "core/hle/kernel/shared_memory.h" |
| 42 | #include "core/hle/kernel/time_manager.h" | 42 | #include "core/hle/kernel/time_manager.h" |
| @@ -66,7 +66,7 @@ struct KernelCore::Impl { | |||
| 66 | is_phantom_mode_for_singlecore = false; | 66 | is_phantom_mode_for_singlecore = false; |
| 67 | 67 | ||
| 68 | InitializePhysicalCores(); | 68 | InitializePhysicalCores(); |
| 69 | InitializeSystemResourceLimit(kernel); | 69 | InitializeSystemResourceLimit(kernel, system); |
| 70 | InitializeMemoryLayout(); | 70 | InitializeMemoryLayout(); |
| 71 | InitializePreemption(kernel); | 71 | InitializePreemption(kernel); |
| 72 | InitializeSchedulers(); | 72 | InitializeSchedulers(); |
| @@ -131,19 +131,23 @@ struct KernelCore::Impl { | |||
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | // Creates the default system resource limit | 133 | // Creates the default system resource limit |
| 134 | void InitializeSystemResourceLimit(KernelCore& kernel) { | 134 | void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) { |
| 135 | system_resource_limit = ResourceLimit::Create(kernel); | 135 | system_resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 136 | 136 | ||
| 137 | // If setting the default system values fails, then something seriously wrong has occurred. | 137 | // If setting the default system values fails, then something seriously wrong has occurred. |
| 138 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000) | 138 | ASSERT( |
| 139 | system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, 0x100000000) | ||
| 140 | .IsSuccess()); | ||
| 141 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800) | ||
| 142 | .IsSuccess()); | ||
| 143 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700) | ||
| 144 | .IsSuccess()); | ||
| 145 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200) | ||
| 146 | .IsSuccess()); | ||
| 147 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 900) | ||
| 139 | .IsSuccess()); | 148 | .IsSuccess()); |
| 140 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess()); | ||
| 141 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess()); | ||
| 142 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess()); | ||
| 143 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); | ||
| 144 | 149 | ||
| 145 | if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) || | 150 | if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, 0x60000)) { |
| 146 | !system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) { | ||
| 147 | UNREACHABLE(); | 151 | UNREACHABLE(); |
| 148 | } | 152 | } |
| 149 | } | 153 | } |
| @@ -320,7 +324,7 @@ struct KernelCore::Impl { | |||
| 320 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 324 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 321 | Kernel::TimeManager time_manager; | 325 | Kernel::TimeManager time_manager; |
| 322 | 326 | ||
| 323 | std::shared_ptr<ResourceLimit> system_resource_limit; | 327 | std::shared_ptr<KResourceLimit> system_resource_limit; |
| 324 | 328 | ||
| 325 | std::shared_ptr<Core::Timing::EventType> preemption_event; | 329 | std::shared_ptr<Core::Timing::EventType> preemption_event; |
| 326 | 330 | ||
| @@ -390,7 +394,7 @@ void KernelCore::Shutdown() { | |||
| 390 | impl->Shutdown(); | 394 | impl->Shutdown(); |
| 391 | } | 395 | } |
| 392 | 396 | ||
| 393 | std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { | 397 | std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const { |
| 394 | return impl->system_resource_limit; | 398 | return impl->system_resource_limit; |
| 395 | } | 399 | } |
| 396 | 400 | ||
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; | |||
| 38 | class HandleTable; | 38 | class HandleTable; |
| 39 | class PhysicalCore; | 39 | class PhysicalCore; |
| 40 | class Process; | 40 | class Process; |
| 41 | class ResourceLimit; | 41 | class KResourceLimit; |
| 42 | class KScheduler; | 42 | class KScheduler; |
| 43 | class SharedMemory; | 43 | class SharedMemory; |
| 44 | class ServiceThread; | 44 | class ServiceThread; |
| @@ -85,7 +85,7 @@ public: | |||
| 85 | void Shutdown(); | 85 | void Shutdown(); |
| 86 | 86 | ||
| 87 | /// Retrieves a shared pointer to the system resource limit instance. | 87 | /// Retrieves a shared pointer to the system resource limit instance. |
| 88 | std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; | 88 | std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const; |
| 89 | 89 | ||
| 90 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | 90 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. |
| 91 | std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; | 91 | 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 @@ | |||
| 7 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 10 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/memory/address_space_info.h" | 12 | #include "core/hle/kernel/memory/address_space_info.h" |
| 12 | #include "core/hle/kernel/memory/memory_block.h" | 13 | #include "core/hle/kernel/memory/memory_block.h" |
| @@ -15,7 +16,6 @@ | |||
| 15 | #include "core/hle/kernel/memory/page_table.h" | 16 | #include "core/hle/kernel/memory/page_table.h" |
| 16 | #include "core/hle/kernel/memory/system_control.h" | 17 | #include "core/hle/kernel/memory/system_control.h" |
| 17 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/resource_limit.h" | ||
| 19 | #include "core/memory.h" | 19 | #include "core/memory.h" |
| 20 | 20 | ||
| 21 | namespace Kernel::Memory { | 21 | namespace Kernel::Memory { |
| @@ -413,8 +413,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 413 | const std::size_t remaining_size{size - mapped_size}; | 413 | const std::size_t remaining_size{size - mapped_size}; |
| 414 | const std::size_t remaining_pages{remaining_size / PageSize}; | 414 | const std::size_t remaining_pages{remaining_size / PageSize}; |
| 415 | 415 | ||
| 416 | if (process->GetResourceLimit() && | 416 | if (process->GetResourceLimit() && !process->GetResourceLimit()->Reserve( |
| 417 | !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) { | 417 | LimitableResource::PhysicalMemoryMax, remaining_size)) { |
| 418 | return ERR_RESOURCE_LIMIT_EXCEEDED; | 418 | return ERR_RESOURCE_LIMIT_EXCEEDED; |
| 419 | } | 419 | } |
| 420 | 420 | ||
| @@ -422,7 +422,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 422 | { | 422 | { |
| 423 | auto block_guard = detail::ScopeExit([&] { | 423 | auto block_guard = detail::ScopeExit([&] { |
| 424 | system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); | 424 | system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); |
| 425 | process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size); | 425 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, |
| 426 | remaining_size); | ||
| 426 | }); | 427 | }); |
| 427 | 428 | ||
| 428 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, | 429 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, |
| @@ -474,7 +475,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 474 | CASCADE_CODE(UnmapMemory(addr, size)); | 475 | CASCADE_CODE(UnmapMemory(addr, size)); |
| 475 | 476 | ||
| 476 | auto process{system.Kernel().CurrentProcess()}; | 477 | auto process{system.Kernel().CurrentProcess()}; |
| 477 | process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size); | 478 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, mapped_size); |
| 478 | physical_memory_usage -= mapped_size; | 479 | physical_memory_usage -= mapped_size; |
| 479 | 480 | ||
| 480 | return RESULT_SUCCESS; | 481 | return RESULT_SUCCESS; |
| @@ -783,7 +784,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) { | |||
| 783 | 784 | ||
| 784 | auto process{system.Kernel().CurrentProcess()}; | 785 | auto process{system.Kernel().CurrentProcess()}; |
| 785 | if (process->GetResourceLimit() && delta != 0 && | 786 | if (process->GetResourceLimit() && delta != 0 && |
| 786 | !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) { | 787 | !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, delta)) { |
| 787 | return ERR_RESOURCE_LIMIT_EXCEEDED; | 788 | return ERR_RESOURCE_LIMIT_EXCEEDED; |
| 788 | } | 789 | } |
| 789 | 790 | ||
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 @@ | |||
| 15 | #include "core/file_sys/program_metadata.h" | 15 | #include "core/file_sys/program_metadata.h" |
| 16 | #include "core/hle/kernel/code_set.h" | 16 | #include "core/hle/kernel/code_set.h" |
| 17 | #include "core/hle/kernel/errors.h" | 17 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 18 | #include "core/hle/kernel/k_scheduler.h" | 19 | #include "core/hle/kernel/k_scheduler.h" |
| 19 | #include "core/hle/kernel/k_thread.h" | 20 | #include "core/hle/kernel/k_thread.h" |
| 20 | #include "core/hle/kernel/kernel.h" | 21 | #include "core/hle/kernel/kernel.h" |
| @@ -22,7 +23,6 @@ | |||
| 22 | #include "core/hle/kernel/memory/page_table.h" | 23 | #include "core/hle/kernel/memory/page_table.h" |
| 23 | #include "core/hle/kernel/memory/slab_heap.h" | 24 | #include "core/hle/kernel/memory/slab_heap.h" |
| 24 | #include "core/hle/kernel/process.h" | 25 | #include "core/hle/kernel/process.h" |
| 25 | #include "core/hle/kernel/resource_limit.h" | ||
| 26 | #include "core/hle/lock.h" | 26 | #include "core/hle/lock.h" |
| 27 | #include "core/memory.h" | 27 | #include "core/memory.h" |
| 28 | #include "core/settings.h" | 28 | #include "core/settings.h" |
| @@ -116,7 +116,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 116 | 116 | ||
| 117 | std::shared_ptr<Process> process = std::make_shared<Process>(system); | 117 | std::shared_ptr<Process> process = std::make_shared<Process>(system); |
| 118 | process->name = std::move(name); | 118 | process->name = std::move(name); |
| 119 | process->resource_limit = ResourceLimit::Create(kernel); | 119 | process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 120 | process->status = ProcessStatus::Created; | 120 | process->status = ProcessStatus::Created; |
| 121 | process->program_id = 0; | 121 | process->program_id = 0; |
| 122 | process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() | 122 | process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() |
| @@ -132,7 +132,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 132 | return process; | 132 | return process; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { | 135 | std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const { |
| 136 | return resource_limit; | 136 | return resource_limit; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| @@ -154,7 +154,7 @@ void Process::DecrementThreadCount() { | |||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | u64 Process::GetTotalPhysicalMemoryAvailable() const { | 156 | u64 Process::GetTotalPhysicalMemoryAvailable() const { |
| 157 | const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) + | 157 | const u64 capacity{resource_limit->GetCurrentValue(LimitableResource::PhysicalMemoryMax) + |
| 158 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + | 158 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + |
| 159 | main_thread_stack_size}; | 159 | main_thread_stack_size}; |
| 160 | 160 | ||
| @@ -308,13 +308,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | |||
| 308 | 308 | ||
| 309 | // Set initial resource limits | 309 | // Set initial resource limits |
| 310 | resource_limit->SetLimitValue( | 310 | resource_limit->SetLimitValue( |
| 311 | ResourceType::PhysicalMemory, | 311 | LimitableResource::PhysicalMemoryMax, |
| 312 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); | 312 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); |
| 313 | resource_limit->SetLimitValue(ResourceType::Threads, 608); | 313 | resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 608); |
| 314 | resource_limit->SetLimitValue(ResourceType::Events, 700); | 314 | resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700); |
| 315 | resource_limit->SetLimitValue(ResourceType::TransferMemory, 128); | 315 | resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 128); |
| 316 | resource_limit->SetLimitValue(ResourceType::Sessions, 894); | 316 | resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 894); |
| 317 | ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size)); | 317 | ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, code_size)); |
| 318 | 318 | ||
| 319 | // Create TLS region | 319 | // Create TLS region |
| 320 | tls_region_address = CreateTLSRegion(); | 320 | tls_region_address = CreateTLSRegion(); |
| @@ -331,8 +331,8 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { | |||
| 331 | ChangeStatus(ProcessStatus::Running); | 331 | ChangeStatus(ProcessStatus::Running); |
| 332 | 332 | ||
| 333 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); | 333 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); |
| 334 | resource_limit->Reserve(ResourceType::Threads, 1); | 334 | resource_limit->Reserve(LimitableResource::ThreadCountMax, 1); |
| 335 | resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size); | 335 | resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size); |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | void Process::PrepareForTermination() { | 338 | 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; | |||
| 29 | namespace Kernel { | 29 | namespace Kernel { |
| 30 | 30 | ||
| 31 | class KernelCore; | 31 | class KernelCore; |
| 32 | class ResourceLimit; | 32 | class KResourceLimit; |
| 33 | class KThread; | 33 | class KThread; |
| 34 | class TLSPage; | 34 | class TLSPage; |
| 35 | 35 | ||
| @@ -170,7 +170,7 @@ public: | |||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | /// Gets the resource limit descriptor for this process | 172 | /// Gets the resource limit descriptor for this process |
| 173 | std::shared_ptr<ResourceLimit> GetResourceLimit() const; | 173 | std::shared_ptr<KResourceLimit> GetResourceLimit() const; |
| 174 | 174 | ||
| 175 | /// Gets the ideal CPU core ID for this process | 175 | /// Gets the ideal CPU core ID for this process |
| 176 | u8 GetIdealCoreId() const { | 176 | u8 GetIdealCoreId() const { |
| @@ -402,7 +402,7 @@ private: | |||
| 402 | u32 system_resource_size = 0; | 402 | u32 system_resource_size = 0; |
| 403 | 403 | ||
| 404 | /// Resource limit descriptor for this process | 404 | /// Resource limit descriptor for this process |
| 405 | std::shared_ptr<ResourceLimit> resource_limit; | 405 | std::shared_ptr<KResourceLimit> resource_limit; |
| 406 | 406 | ||
| 407 | /// The ideal CPU core for this process, threads are scheduled on this core by default. | 407 | /// The ideal CPU core for this process, threads are scheduled on this core by default. |
| 408 | u8 ideal_core = 0; | 408 | 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 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/errors.h" | ||
| 6 | #include "core/hle/kernel/resource_limit.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | namespace { | ||
| 11 | constexpr std::size_t ResourceTypeToIndex(ResourceType type) { | ||
| 12 | return static_cast<std::size_t>(type); | ||
| 13 | } | ||
| 14 | } // Anonymous namespace | ||
| 15 | |||
| 16 | ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} | ||
| 17 | ResourceLimit::~ResourceLimit() = default; | ||
| 18 | |||
| 19 | bool ResourceLimit::Reserve(ResourceType resource, s64 amount) { | ||
| 20 | return Reserve(resource, amount, 10000000000); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) { | ||
| 24 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 25 | |||
| 26 | s64 new_value = current[index] + amount; | ||
| 27 | if (new_value > limit[index] && available[index] + amount <= limit[index]) { | ||
| 28 | // TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout | ||
| 29 | new_value = current[index] + amount; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (new_value <= limit[index]) { | ||
| 33 | current[index] = new_value; | ||
| 34 | return true; | ||
| 35 | } | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | |||
| 39 | void ResourceLimit::Release(ResourceType resource, u64 amount) { | ||
| 40 | Release(resource, amount, amount); | ||
| 41 | } | ||
| 42 | |||
| 43 | void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) { | ||
| 44 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 45 | |||
| 46 | current[index] -= used_amount; | ||
| 47 | available[index] -= available_amount; | ||
| 48 | } | ||
| 49 | |||
| 50 | std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { | ||
| 51 | return std::make_shared<ResourceLimit>(kernel); | ||
| 52 | } | ||
| 53 | |||
| 54 | s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | ||
| 55 | return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource)); | ||
| 56 | } | ||
| 57 | |||
| 58 | s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | ||
| 59 | return limit.at(ResourceTypeToIndex(resource)); | ||
| 60 | } | ||
| 61 | |||
| 62 | ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) { | ||
| 63 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 64 | if (current[index] <= value) { | ||
| 65 | limit[index] = value; | ||
| 66 | return RESULT_SUCCESS; | ||
| 67 | } else { | ||
| 68 | LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource, | ||
| 69 | value, index); | ||
| 70 | return ERR_INVALID_STATE; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } // 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 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <memory> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | |||
| 13 | union ResultCode; | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | class KernelCore; | ||
| 18 | |||
| 19 | enum class ResourceType : u32 { | ||
| 20 | PhysicalMemory, | ||
| 21 | Threads, | ||
| 22 | Events, | ||
| 23 | TransferMemory, | ||
| 24 | Sessions, | ||
| 25 | |||
| 26 | // Used as a count, not an actual type. | ||
| 27 | ResourceTypeCount | ||
| 28 | }; | ||
| 29 | |||
| 30 | constexpr bool IsValidResourceType(ResourceType type) { | ||
| 31 | return type < ResourceType::ResourceTypeCount; | ||
| 32 | } | ||
| 33 | |||
| 34 | class ResourceLimit final : public Object { | ||
| 35 | public: | ||
| 36 | explicit ResourceLimit(KernelCore& kernel); | ||
| 37 | ~ResourceLimit() override; | ||
| 38 | |||
| 39 | /// Creates a resource limit object. | ||
| 40 | static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel); | ||
| 41 | |||
| 42 | std::string GetTypeName() const override { | ||
| 43 | return "ResourceLimit"; | ||
| 44 | } | ||
| 45 | std::string GetName() const override { | ||
| 46 | return GetTypeName(); | ||
| 47 | } | ||
| 48 | |||
| 49 | static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; | ||
| 50 | HandleType GetHandleType() const override { | ||
| 51 | return HANDLE_TYPE; | ||
| 52 | } | ||
| 53 | |||
| 54 | bool Reserve(ResourceType resource, s64 amount); | ||
| 55 | bool Reserve(ResourceType resource, s64 amount, u64 timeout); | ||
| 56 | void Release(ResourceType resource, u64 amount); | ||
| 57 | void Release(ResourceType resource, u64 used_amount, u64 available_amount); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Gets the current value for the specified resource. | ||
| 61 | * @param resource Requested resource type | ||
| 62 | * @returns The current value of the resource type | ||
| 63 | */ | ||
| 64 | s64 GetCurrentResourceValue(ResourceType resource) const; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Gets the max value for the specified resource. | ||
| 68 | * @param resource Requested resource type | ||
| 69 | * @returns The max value of the resource type | ||
| 70 | */ | ||
| 71 | s64 GetMaxResourceValue(ResourceType resource) const; | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Sets the limit value for a given resource type. | ||
| 75 | * | ||
| 76 | * @param resource The resource type to apply the limit to. | ||
| 77 | * @param value The limit to apply to the given resource type. | ||
| 78 | * | ||
| 79 | * @return A result code indicating if setting the limit value | ||
| 80 | * was successful or not. | ||
| 81 | * | ||
| 82 | * @note The supplied limit value *must* be greater than or equal to | ||
| 83 | * the current resource value for the given resource type, | ||
| 84 | * otherwise ERR_INVALID_STATE will be returned. | ||
| 85 | */ | ||
| 86 | ResultCode SetLimitValue(ResourceType resource, s64 value); | ||
| 87 | |||
| 88 | void Finalize() override {} | ||
| 89 | |||
| 90 | private: | ||
| 91 | // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create | ||
| 92 | // functions | ||
| 93 | // | ||
| 94 | // Currently we have no way of distinguishing if a Create was called by the running application, | ||
| 95 | // or by a service module. Approach this once we have separated the service modules into their | ||
| 96 | // own processes | ||
| 97 | |||
| 98 | using ResourceArray = | ||
| 99 | std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>; | ||
| 100 | |||
| 101 | ResourceArray limit{}; | ||
| 102 | ResourceArray current{}; | ||
| 103 | ResourceArray available{}; | ||
| 104 | }; | ||
| 105 | |||
| 106 | } // 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 @@ | |||
| 26 | #include "core/hle/kernel/handle_table.h" | 26 | #include "core/hle/kernel/handle_table.h" |
| 27 | #include "core/hle/kernel/k_address_arbiter.h" | 27 | #include "core/hle/kernel/k_address_arbiter.h" |
| 28 | #include "core/hle/kernel/k_condition_variable.h" | 28 | #include "core/hle/kernel/k_condition_variable.h" |
| 29 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 29 | #include "core/hle/kernel/k_scheduler.h" | 30 | #include "core/hle/kernel/k_scheduler.h" |
| 30 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 31 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 31 | #include "core/hle/kernel/k_synchronization_object.h" | 32 | #include "core/hle/kernel/k_synchronization_object.h" |
| @@ -37,7 +38,6 @@ | |||
| 37 | #include "core/hle/kernel/physical_core.h" | 38 | #include "core/hle/kernel/physical_core.h" |
| 38 | #include "core/hle/kernel/process.h" | 39 | #include "core/hle/kernel/process.h" |
| 39 | #include "core/hle/kernel/readable_event.h" | 40 | #include "core/hle/kernel/readable_event.h" |
| 40 | #include "core/hle/kernel/resource_limit.h" | ||
| 41 | #include "core/hle/kernel/shared_memory.h" | 41 | #include "core/hle/kernel/shared_memory.h" |
| 42 | #include "core/hle/kernel/svc.h" | 42 | #include "core/hle/kernel/svc.h" |
| 43 | #include "core/hle/kernel/svc_results.h" | 43 | #include "core/hle/kernel/svc_results.h" |
| @@ -141,7 +141,7 @@ enum class ResourceLimitValueType { | |||
| 141 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, | 141 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, |
| 142 | u32 resource_type, ResourceLimitValueType value_type) { | 142 | u32 resource_type, ResourceLimitValueType value_type) { |
| 143 | std::lock_guard lock{HLE::g_hle_lock}; | 143 | std::lock_guard lock{HLE::g_hle_lock}; |
| 144 | const auto type = static_cast<ResourceType>(resource_type); | 144 | const auto type = static_cast<LimitableResource>(resource_type); |
| 145 | if (!IsValidResourceType(type)) { | 145 | if (!IsValidResourceType(type)) { |
| 146 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | 146 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); |
| 147 | return ERR_INVALID_ENUM_VALUE; | 147 | return ERR_INVALID_ENUM_VALUE; |
| @@ -151,7 +151,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_ | |||
| 151 | ASSERT(current_process != nullptr); | 151 | ASSERT(current_process != nullptr); |
| 152 | 152 | ||
| 153 | const auto resource_limit_object = | 153 | const auto resource_limit_object = |
| 154 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | 154 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); |
| 155 | if (!resource_limit_object) { | 155 | if (!resource_limit_object) { |
| 156 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | 156 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", |
| 157 | resource_limit); | 157 | resource_limit); |
| @@ -159,10 +159,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_ | |||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | if (value_type == ResourceLimitValueType::CurrentValue) { | 161 | if (value_type == ResourceLimitValueType::CurrentValue) { |
| 162 | return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); | 162 | return MakeResult(resource_limit_object->GetCurrentValue(type)); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | return MakeResult(resource_limit_object->GetMaxResourceValue(type)); | 165 | return MakeResult(resource_limit_object->GetLimitValue(type)); |
| 166 | } | 166 | } |
| 167 | } // Anonymous namespace | 167 | } // Anonymous namespace |
| 168 | 168 | ||
| @@ -312,7 +312,8 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | |||
| 312 | return ERR_NOT_FOUND; | 312 | return ERR_NOT_FOUND; |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1)); | 315 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::SessionCountMax, |
| 316 | 1)); | ||
| 316 | 317 | ||
| 317 | auto client_port = it->second; | 318 | auto client_port = it->second; |
| 318 | 319 | ||
| @@ -1450,7 +1451,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1450 | Svc::ResultInvalidPriority); | 1451 | Svc::ResultInvalidPriority); |
| 1451 | R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); | 1452 | R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); |
| 1452 | 1453 | ||
| 1453 | ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1)); | 1454 | ASSERT(process.GetResourceLimit()->Reserve( |
| 1455 | LimitableResource::ThreadCountMax, 1, | ||
| 1456 | system.CoreTiming().GetClockTicks() + | ||
| 1457 | Core::Timing::msToCycles(std::chrono::milliseconds{100}))); | ||
| 1454 | 1458 | ||
| 1455 | std::shared_ptr<KThread> thread; | 1459 | std::shared_ptr<KThread> thread; |
| 1456 | { | 1460 | { |
| @@ -1972,7 +1976,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) | |||
| 1972 | LOG_DEBUG(Kernel_SVC, "called"); | 1976 | LOG_DEBUG(Kernel_SVC, "called"); |
| 1973 | 1977 | ||
| 1974 | auto& kernel = system.Kernel(); | 1978 | auto& kernel = system.Kernel(); |
| 1975 | auto resource_limit = ResourceLimit::Create(kernel); | 1979 | auto resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 1976 | 1980 | ||
| 1977 | auto* const current_process = kernel.CurrentProcess(); | 1981 | auto* const current_process = kernel.CurrentProcess(); |
| 1978 | ASSERT(current_process != nullptr); | 1982 | ASSERT(current_process != nullptr); |
| @@ -2019,7 +2023,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2019 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | 2023 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, |
| 2020 | resource_type, value); | 2024 | resource_type, value); |
| 2021 | 2025 | ||
| 2022 | const auto type = static_cast<ResourceType>(resource_type); | 2026 | const auto type = static_cast<LimitableResource>(resource_type); |
| 2023 | if (!IsValidResourceType(type)) { | 2027 | if (!IsValidResourceType(type)) { |
| 2024 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | 2028 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); |
| 2025 | return ERR_INVALID_ENUM_VALUE; | 2029 | return ERR_INVALID_ENUM_VALUE; |
| @@ -2029,7 +2033,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2029 | ASSERT(current_process != nullptr); | 2033 | ASSERT(current_process != nullptr); |
| 2030 | 2034 | ||
| 2031 | auto resource_limit_object = | 2035 | auto resource_limit_object = |
| 2032 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | 2036 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); |
| 2033 | if (!resource_limit_object) { | 2037 | if (!resource_limit_object) { |
| 2034 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | 2038 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", |
| 2035 | resource_limit); | 2039 | resource_limit); |
| @@ -2041,8 +2045,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2041 | LOG_ERROR( | 2045 | LOG_ERROR( |
| 2042 | Kernel_SVC, | 2046 | Kernel_SVC, |
| 2043 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", | 2047 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", |
| 2044 | resource_limit_object->GetMaxResourceValue(type), resource_type, | 2048 | resource_limit_object->GetLimitValue(type), resource_type, |
| 2045 | resource_limit_object->GetCurrentResourceValue(type)); | 2049 | resource_limit_object->GetCurrentValue(type)); |
| 2046 | return set_result; | 2050 | return set_result; |
| 2047 | } | 2051 | } |
| 2048 | 2052 | ||