Merge pull request #1738 from lioncash/res-limit
kernel/resource_limit: Clean up interface
This commit is contained in:
		| @@ -105,7 +105,7 @@ struct KernelCore::Impl { | ||||
|     void Initialize(KernelCore& kernel) { | ||||
|         Shutdown(); | ||||
|  | ||||
|         InitializeResourceLimits(kernel); | ||||
|         InitializeSystemResourceLimit(kernel); | ||||
|         InitializeThreads(); | ||||
|         InitializeTimers(); | ||||
|     } | ||||
| @@ -118,7 +118,7 @@ struct KernelCore::Impl { | ||||
|         process_list.clear(); | ||||
|         current_process = nullptr; | ||||
|  | ||||
|         resource_limits.fill(nullptr); | ||||
|         system_resource_limit = nullptr; | ||||
|  | ||||
|         thread_wakeup_callback_handle_table.Clear(); | ||||
|         thread_wakeup_event_type = nullptr; | ||||
| @@ -129,63 +129,17 @@ struct KernelCore::Impl { | ||||
|         named_ports.clear(); | ||||
|     } | ||||
|  | ||||
|     void InitializeResourceLimits(KernelCore& kernel) { | ||||
|         // Create the four resource limits that the system uses | ||||
|         // Create the APPLICATION resource limit | ||||
|         SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications"); | ||||
|         resource_limit->max_priority = 0x18; | ||||
|         resource_limit->max_commit = 0x4000000; | ||||
|         resource_limit->max_threads = 0x20; | ||||
|         resource_limit->max_events = 0x20; | ||||
|         resource_limit->max_mutexes = 0x20; | ||||
|         resource_limit->max_semaphores = 0x8; | ||||
|         resource_limit->max_timers = 0x8; | ||||
|         resource_limit->max_shared_mems = 0x10; | ||||
|         resource_limit->max_address_arbiters = 0x2; | ||||
|         resource_limit->max_cpu_time = 0x1E; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit; | ||||
|     // Creates the default system resource limit | ||||
|     void InitializeSystemResourceLimit(KernelCore& kernel) { | ||||
|         system_resource_limit = ResourceLimit::Create(kernel, "System"); | ||||
|  | ||||
|         // Create the SYS_APPLET resource limit | ||||
|         resource_limit = ResourceLimit::Create(kernel, "System Applets"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x5E00000; | ||||
|         resource_limit->max_threads = 0x1D; | ||||
|         resource_limit->max_events = 0xB; | ||||
|         resource_limit->max_mutexes = 0x8; | ||||
|         resource_limit->max_semaphores = 0x4; | ||||
|         resource_limit->max_timers = 0x4; | ||||
|         resource_limit->max_shared_mems = 0x8; | ||||
|         resource_limit->max_address_arbiters = 0x3; | ||||
|         resource_limit->max_cpu_time = 0x2710; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit; | ||||
|  | ||||
|         // Create the LIB_APPLET resource limit | ||||
|         resource_limit = ResourceLimit::Create(kernel, "Library Applets"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x600000; | ||||
|         resource_limit->max_threads = 0xE; | ||||
|         resource_limit->max_events = 0x8; | ||||
|         resource_limit->max_mutexes = 0x8; | ||||
|         resource_limit->max_semaphores = 0x4; | ||||
|         resource_limit->max_timers = 0x4; | ||||
|         resource_limit->max_shared_mems = 0x8; | ||||
|         resource_limit->max_address_arbiters = 0x1; | ||||
|         resource_limit->max_cpu_time = 0x2710; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit; | ||||
|  | ||||
|         // Create the OTHER resource limit | ||||
|         resource_limit = ResourceLimit::Create(kernel, "Others"); | ||||
|         resource_limit->max_priority = 0x4; | ||||
|         resource_limit->max_commit = 0x2180000; | ||||
|         resource_limit->max_threads = 0xE1; | ||||
|         resource_limit->max_events = 0x108; | ||||
|         resource_limit->max_mutexes = 0x25; | ||||
|         resource_limit->max_semaphores = 0x43; | ||||
|         resource_limit->max_timers = 0x2C; | ||||
|         resource_limit->max_shared_mems = 0x1F; | ||||
|         resource_limit->max_address_arbiters = 0x2D; | ||||
|         resource_limit->max_cpu_time = 0x3E8; | ||||
|         resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit; | ||||
|         // If setting the default system values fails, then something seriously wrong has occurred. | ||||
|         ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000) | ||||
|                    .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()); | ||||
|     } | ||||
|  | ||||
|     void InitializeThreads() { | ||||
| @@ -208,7 +162,7 @@ struct KernelCore::Impl { | ||||
|     std::vector<SharedPtr<Process>> process_list; | ||||
|     Process* current_process = nullptr; | ||||
|  | ||||
|     std::array<SharedPtr<ResourceLimit>, 4> resource_limits; | ||||
|     SharedPtr<ResourceLimit> system_resource_limit; | ||||
|  | ||||
|     /// The event type of the generic timer callback event | ||||
|     CoreTiming::EventType* timer_callback_event_type = nullptr; | ||||
| @@ -239,9 +193,8 @@ void KernelCore::Shutdown() { | ||||
|     impl->Shutdown(); | ||||
| } | ||||
|  | ||||
| SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( | ||||
|     ResourceLimitCategory category) const { | ||||
|     return impl->resource_limits.at(static_cast<std::size_t>(category)); | ||||
| SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { | ||||
|     return impl->system_resource_limit; | ||||
| } | ||||
|  | ||||
| SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { | ||||
|   | ||||
| @@ -24,8 +24,6 @@ class ResourceLimit; | ||||
| class Thread; | ||||
| class Timer; | ||||
|  | ||||
| enum class ResourceLimitCategory : u8; | ||||
|  | ||||
| /// Represents a single instance of the kernel. | ||||
| class KernelCore { | ||||
| private: | ||||
| @@ -47,8 +45,8 @@ public: | ||||
|     /// Clears all resources in use by the kernel instance. | ||||
|     void Shutdown(); | ||||
|  | ||||
|     /// Retrieves a shared pointer to a ResourceLimit identified by the given category. | ||||
|     SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; | ||||
|     /// Retrieves a shared pointer to the system resource limit instance. | ||||
|     SharedPtr<ResourceLimit> GetSystemResourceLimit() const; | ||||
|  | ||||
|     /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | ||||
|     SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; | ||||
|   | ||||
| @@ -28,7 +28,7 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | ||||
|     process->name = std::move(name); | ||||
|     process->flags.raw = 0; | ||||
|     process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | ||||
|     process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); | ||||
|     process->resource_limit = kernel.GetSystemResourceLimit(); | ||||
|     process->status = ProcessStatus::Created; | ||||
|     process->program_id = 0; | ||||
|     process->process_id = kernel.CreateNewProcessID(); | ||||
|   | ||||
| @@ -2,12 +2,16 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <cstring> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #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; | ||||
| @@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n | ||||
|     return resource_limit; | ||||
| } | ||||
|  | ||||
| s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | ||||
|     switch (resource) { | ||||
|     case ResourceType::Commit: | ||||
|         return current_commit; | ||||
|     case ResourceType::Thread: | ||||
|         return current_threads; | ||||
|     case ResourceType::Event: | ||||
|         return current_events; | ||||
|     case ResourceType::Mutex: | ||||
|         return current_mutexes; | ||||
|     case ResourceType::Semaphore: | ||||
|         return current_semaphores; | ||||
|     case ResourceType::Timer: | ||||
|         return current_timers; | ||||
|     case ResourceType::SharedMemory: | ||||
|         return current_shared_mems; | ||||
|     case ResourceType::AddressArbiter: | ||||
|         return current_address_arbiters; | ||||
|     case ResourceType::CPUTime: | ||||
|         return current_cpu_time; | ||||
|     default: | ||||
|         LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | ||||
|         UNIMPLEMENTED(); | ||||
|         return 0; | ||||
|     } | ||||
| s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | ||||
|     return values.at(ResourceTypeToIndex(resource)); | ||||
| } | ||||
|  | ||||
| u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | ||||
|     switch (resource) { | ||||
|     case ResourceType::Priority: | ||||
|         return max_priority; | ||||
|     case ResourceType::Commit: | ||||
|         return max_commit; | ||||
|     case ResourceType::Thread: | ||||
|         return max_threads; | ||||
|     case ResourceType::Event: | ||||
|         return max_events; | ||||
|     case ResourceType::Mutex: | ||||
|         return max_mutexes; | ||||
|     case ResourceType::Semaphore: | ||||
|         return max_semaphores; | ||||
|     case ResourceType::Timer: | ||||
|         return max_timers; | ||||
|     case ResourceType::SharedMemory: | ||||
|         return max_shared_mems; | ||||
|     case ResourceType::AddressArbiter: | ||||
|         return max_address_arbiters; | ||||
|     case ResourceType::CPUTime: | ||||
|         return max_cpu_time; | ||||
|     default: | ||||
|         LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | ||||
|         UNIMPLEMENTED(); | ||||
|         return 0; | ||||
| s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | ||||
|     return limits.at(ResourceTypeToIndex(resource)); | ||||
| } | ||||
|  | ||||
| ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) { | ||||
|     const auto index = ResourceTypeToIndex(resource); | ||||
|  | ||||
|     if (value < values[index]) { | ||||
|         return ERR_INVALID_STATE; | ||||
|     } | ||||
|  | ||||
|     values[index] = value; | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -4,31 +4,25 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
|  | ||||
| union ResultCode; | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class KernelCore; | ||||
|  | ||||
| enum class ResourceLimitCategory : u8 { | ||||
|     APPLICATION = 0, | ||||
|     SYS_APPLET = 1, | ||||
|     LIB_APPLET = 2, | ||||
|     OTHER = 3 | ||||
| }; | ||||
|  | ||||
| enum class ResourceType { | ||||
|     Priority = 0, | ||||
|     Commit = 1, | ||||
|     Thread = 2, | ||||
|     Event = 3, | ||||
|     Mutex = 4, | ||||
|     Semaphore = 5, | ||||
|     Timer = 6, | ||||
|     SharedMemory = 7, | ||||
|     AddressArbiter = 8, | ||||
|     CPUTime = 9, | ||||
|     PhysicalMemory, | ||||
|     Threads, | ||||
|     Events, | ||||
|     TransferMemory, | ||||
|     Sessions, | ||||
|  | ||||
|     // Used as a count, not an actual type. | ||||
|     ResourceTypeCount | ||||
| }; | ||||
|  | ||||
| class ResourceLimit final : public Object { | ||||
| @@ -55,61 +49,51 @@ public: | ||||
|      * @param resource Requested resource type | ||||
|      * @returns The current value of the resource type | ||||
|      */ | ||||
|     s32 GetCurrentResourceValue(ResourceType resource) const; | ||||
|     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 | ||||
|      */ | ||||
|     u32 GetMaxResourceValue(ResourceType resource) const; | ||||
|     s64 GetMaxResourceValue(ResourceType resource) const; | ||||
|  | ||||
|     /// Name of resource limit object. | ||||
|     std::string name; | ||||
|  | ||||
|     /// Max thread priority that a process in this category can create | ||||
|     s32 max_priority = 0; | ||||
|  | ||||
|     /// Max memory that processes in this category can use | ||||
|     s32 max_commit = 0; | ||||
|  | ||||
|     ///< Max number of objects that can be collectively created by the processes in this category | ||||
|     s32 max_threads = 0; | ||||
|     s32 max_events = 0; | ||||
|     s32 max_mutexes = 0; | ||||
|     s32 max_semaphores = 0; | ||||
|     s32 max_timers = 0; | ||||
|     s32 max_shared_mems = 0; | ||||
|     s32 max_address_arbiters = 0; | ||||
|  | ||||
|     /// Max CPU time that the processes in this category can utilize | ||||
|     s32 max_cpu_time = 0; | ||||
|  | ||||
|     // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind | ||||
|     // that APPLICATION resource limits should not be affected by the objects created by service | ||||
|     // modules. | ||||
|     // 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 | ||||
|  | ||||
|     /// Current memory that the processes in this category are using | ||||
|     s32 current_commit = 0; | ||||
|  | ||||
|     ///< Current number of objects among all processes in this category | ||||
|     s32 current_threads = 0; | ||||
|     s32 current_events = 0; | ||||
|     s32 current_mutexes = 0; | ||||
|     s32 current_semaphores = 0; | ||||
|     s32 current_timers = 0; | ||||
|     s32 current_shared_mems = 0; | ||||
|     s32 current_address_arbiters = 0; | ||||
|  | ||||
|     /// Current CPU time that the processes in this category are utilizing | ||||
|     s32 current_cpu_time = 0; | ||||
|     /** | ||||
|      * 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); | ||||
|  | ||||
| private: | ||||
|     explicit ResourceLimit(KernelCore& kernel); | ||||
|     ~ResourceLimit() override; | ||||
|  | ||||
|     // 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)>; | ||||
|  | ||||
|     /// Maximum values a resource type may reach. | ||||
|     ResourceArray limits{}; | ||||
|     /// Current resource limit values. | ||||
|     ResourceArray values{}; | ||||
|  | ||||
|     /// Name of resource limit object. | ||||
|     std::string name; | ||||
| }; | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -736,13 +736,6 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | ||||
|  | ||||
|     const auto* const current_process = Core::CurrentProcess(); | ||||
|  | ||||
|     // Note: The kernel uses the current process's resource limit instead of | ||||
|     // the one from the thread owner's resource limit. | ||||
|     const ResourceLimit& resource_limit = current_process->GetResourceLimit(); | ||||
|     if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { | ||||
|         return ERR_INVALID_THREAD_PRIORITY; | ||||
|     } | ||||
|  | ||||
|     SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | ||||
|     if (!thread) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
| @@ -885,10 +878,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | ||||
|     } | ||||
|  | ||||
|     auto* const current_process = Core::CurrentProcess(); | ||||
|     const ResourceLimit& resource_limit = current_process->GetResourceLimit(); | ||||
|     if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { | ||||
|         return ERR_INVALID_THREAD_PRIORITY; | ||||
|     } | ||||
|  | ||||
|     if (processor_id == THREADPROCESSORID_DEFAULT) { | ||||
|         // Set the target CPU to the one specified in the process' exheader. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user