Merge pull request #1738 from lioncash/res-limit
kernel/resource_limit: Clean up interface
This commit is contained in:
commit
2caac4a395
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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:
|
ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
|
||||||
return max_commit;
|
const auto index = ResourceTypeToIndex(resource);
|
||||||
case ResourceType::Thread:
|
|
||||||
return max_threads;
|
if (value < values[index]) {
|
||||||
case ResourceType::Event:
|
return ERR_INVALID_STATE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
values[index] = value;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue