Merge pull request #1738 from lioncash/res-limit

kernel/resource_limit: Clean up interface
This commit is contained in:
bunnei 2018-11-19 18:40:02 -08:00 committed by GitHub
commit 2caac4a395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 193 deletions

View File

@ -105,7 +105,7 @@ struct KernelCore::Impl {
void Initialize(KernelCore& kernel) { void Initialize(KernelCore& kernel) {
Shutdown(); Shutdown();
InitializeResourceLimits(kernel); InitializeSystemResourceLimit(kernel);
InitializeThreads(); InitializeThreads();
InitializeTimers(); InitializeTimers();
} }
@ -118,7 +118,7 @@ struct KernelCore::Impl {
process_list.clear(); process_list.clear();
current_process = nullptr; current_process = nullptr;
resource_limits.fill(nullptr); system_resource_limit = nullptr;
thread_wakeup_callback_handle_table.Clear(); thread_wakeup_callback_handle_table.Clear();
thread_wakeup_event_type = nullptr; thread_wakeup_event_type = nullptr;
@ -129,63 +129,17 @@ struct KernelCore::Impl {
named_ports.clear(); named_ports.clear();
} }
void InitializeResourceLimits(KernelCore& kernel) { // Creates the default system resource limit
// Create the four resource limits that the system uses void InitializeSystemResourceLimit(KernelCore& kernel) {
// Create the APPLICATION resource limit system_resource_limit = ResourceLimit::Create(kernel, "System");
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;
// Create the SYS_APPLET resource limit // If setting the default system values fails, then something seriously wrong has occurred.
resource_limit = ResourceLimit::Create(kernel, "System Applets"); ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
resource_limit->max_priority = 0x4; .IsSuccess());
resource_limit->max_commit = 0x5E00000; ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
resource_limit->max_threads = 0x1D; ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
resource_limit->max_events = 0xB; ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
resource_limit->max_mutexes = 0x8; ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
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;
} }
void InitializeThreads() { void InitializeThreads() {
@ -208,7 +162,7 @@ struct KernelCore::Impl {
std::vector<SharedPtr<Process>> process_list; std::vector<SharedPtr<Process>> process_list;
Process* current_process = nullptr; 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 /// The event type of the generic timer callback event
CoreTiming::EventType* timer_callback_event_type = nullptr; CoreTiming::EventType* timer_callback_event_type = nullptr;
@ -239,9 +193,8 @@ void KernelCore::Shutdown() {
impl->Shutdown(); impl->Shutdown();
} }
SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
ResourceLimitCategory category) const { return impl->system_resource_limit;
return impl->resource_limits.at(static_cast<std::size_t>(category));
} }
SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {

View File

@ -24,8 +24,6 @@ class ResourceLimit;
class Thread; class Thread;
class Timer; class Timer;
enum class ResourceLimitCategory : u8;
/// Represents a single instance of the kernel. /// Represents a single instance of the kernel.
class KernelCore { class KernelCore {
private: private:
@ -47,8 +45,8 @@ public:
/// Clears all resources in use by the kernel instance. /// Clears all resources in use by the kernel instance.
void Shutdown(); void Shutdown();
/// Retrieves a shared pointer to a ResourceLimit identified by the given category. /// Retrieves a shared pointer to the system resource limit instance.
SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; SharedPtr<ResourceLimit> GetSystemResourceLimit() const;
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;

View File

@ -28,7 +28,7 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
process->name = std::move(name); process->name = std::move(name);
process->flags.raw = 0; process->flags.raw = 0;
process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created; process->status = ProcessStatus::Created;
process->program_id = 0; process->program_id = 0;
process->process_id = kernel.CreateNewProcessID(); process->process_id = kernel.CreateNewProcessID();

View File

@ -2,12 +2,16 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring> #include "core/hle/kernel/errors.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/result.h"
namespace Kernel { 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(KernelCore& kernel) : Object{kernel} {}
ResourceLimit::~ResourceLimit() = default; ResourceLimit::~ResourceLimit() = default;
@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n
return resource_limit; return resource_limit;
} }
s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
switch (resource) { return values.at(ResourceTypeToIndex(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;
}
} }
u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
switch (resource) { return limits.at(ResourceTypeToIndex(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;
} }
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 } // namespace Kernel

View File

@ -4,31 +4,25 @@
#pragma once #pragma once
#include <array>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
union ResultCode;
namespace Kernel { namespace Kernel {
class KernelCore; class KernelCore;
enum class ResourceLimitCategory : u8 {
APPLICATION = 0,
SYS_APPLET = 1,
LIB_APPLET = 2,
OTHER = 3
};
enum class ResourceType { enum class ResourceType {
Priority = 0, PhysicalMemory,
Commit = 1, Threads,
Thread = 2, Events,
Event = 3, TransferMemory,
Mutex = 4, Sessions,
Semaphore = 5,
Timer = 6, // Used as a count, not an actual type.
SharedMemory = 7, ResourceTypeCount
AddressArbiter = 8,
CPUTime = 9,
}; };
class ResourceLimit final : public Object { class ResourceLimit final : public Object {
@ -55,61 +49,51 @@ public:
* @param resource Requested resource type * @param resource Requested resource type
* @returns The current value of the 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. * Gets the max value for the specified resource.
* @param resource Requested resource type * @param resource Requested resource type
* @returns The max value of the 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; * Sets the limit value for a given resource type.
*
/// Max thread priority that a process in this category can create * @param resource The resource type to apply the limit to.
s32 max_priority = 0; * @param value The limit to apply to the given resource type.
*
/// Max memory that processes in this category can use * @return A result code indicating if setting the limit value
s32 max_commit = 0; * was successful or not.
*
///< Max number of objects that can be collectively created by the processes in this category * @note The supplied limit value *must* be greater than or equal to
s32 max_threads = 0; * the current resource value for the given resource type,
s32 max_events = 0; * otherwise ERR_INVALID_STATE will be returned.
s32 max_mutexes = 0; */
s32 max_semaphores = 0; ResultCode SetLimitValue(ResourceType resource, s64 value);
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;
private: private:
explicit ResourceLimit(KernelCore& kernel); explicit ResourceLimit(KernelCore& kernel);
~ResourceLimit() override; ~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 } // namespace Kernel

View File

@ -736,13 +736,6 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
const auto* const current_process = Core::CurrentProcess(); 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); SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
if (!thread) { if (!thread) {
return ERR_INVALID_HANDLE; 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(); 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) { if (processor_id == THREADPROCESSORID_DEFAULT) {
// Set the target CPU to the one specified in the process' exheader. // Set the target CPU to the one specified in the process' exheader.