kernel: Rewrite resource limit to be more accurate
Matches closer to hardware
This commit is contained in:
parent
a4526c4e1a
commit
3be1a565f8
|
@ -160,9 +160,12 @@ add_library(core STATIC
|
||||||
hle/kernel/k_affinity_mask.h
|
hle/kernel/k_affinity_mask.h
|
||||||
hle/kernel/k_condition_variable.cpp
|
hle/kernel/k_condition_variable.cpp
|
||||||
hle/kernel/k_condition_variable.h
|
hle/kernel/k_condition_variable.h
|
||||||
|
hle/kernel/k_light_condition_variable.h
|
||||||
hle/kernel/k_light_lock.cpp
|
hle/kernel/k_light_lock.cpp
|
||||||
hle/kernel/k_light_lock.h
|
hle/kernel/k_light_lock.h
|
||||||
hle/kernel/k_priority_queue.h
|
hle/kernel/k_priority_queue.h
|
||||||
|
hle/kernel/k_resource_limit.cpp
|
||||||
|
hle/kernel/k_resource_limit.h
|
||||||
hle/kernel/k_scheduler.cpp
|
hle/kernel/k_scheduler.cpp
|
||||||
hle/kernel/k_scheduler.h
|
hle/kernel/k_scheduler.h
|
||||||
hle/kernel/k_scheduler_lock.h
|
hle/kernel/k_scheduler_lock.h
|
||||||
|
@ -203,8 +206,6 @@ add_library(core STATIC
|
||||||
hle/kernel/process_capability.h
|
hle/kernel/process_capability.h
|
||||||
hle/kernel/readable_event.cpp
|
hle/kernel/readable_event.cpp
|
||||||
hle/kernel/readable_event.h
|
hle/kernel/readable_event.h
|
||||||
hle/kernel/resource_limit.cpp
|
|
||||||
hle/kernel/resource_limit.h
|
|
||||||
hle/kernel/server_port.cpp
|
hle/kernel/server_port.cpp
|
||||||
hle/kernel/server_port.h
|
hle/kernel/server_port.h
|
||||||
hle/kernel/server_session.cpp
|
hle/kernel/server_session.cpp
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||||
|
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
|
#include "core/hle/kernel/k_thread_queue.h"
|
||||||
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KernelCore;
|
||||||
|
|
||||||
|
class KLightConditionVariable {
|
||||||
|
private:
|
||||||
|
KThreadQueue m_thread_queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
KLightConditionVariable(KernelCore& kernel) : m_thread_queue(kernel), kernel(kernel) {}
|
||||||
|
|
||||||
|
void Wait(KLightLock* lock, s64 timeout = -1ll) {
|
||||||
|
WaitImpl(lock, timeout);
|
||||||
|
lock->Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcast() {
|
||||||
|
KScopedSchedulerLock lk{kernel};
|
||||||
|
while (m_thread_queue.WakeupFrontThread() != nullptr) {
|
||||||
|
/* We want to signal all threads, and so should continue waking up until there's nothing
|
||||||
|
* to wake. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void WaitImpl(KLightLock* lock, s64 timeout) {
|
||||||
|
KThread* owner = GetCurrentThreadPointer(kernel);
|
||||||
|
// KHardwareTimer* timer;
|
||||||
|
|
||||||
|
/* Sleep the thread. */
|
||||||
|
{
|
||||||
|
KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
|
||||||
|
lock->Unlock();
|
||||||
|
|
||||||
|
if (!m_thread_queue.SleepThread(owner)) {
|
||||||
|
lk.CancelSleep();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel the task that the sleep setup. */
|
||||||
|
kernel.TimeManager().UnscheduleTimeEvent(owner);
|
||||||
|
}
|
||||||
|
KernelCore& kernel;
|
||||||
|
};
|
||||||
|
} // namespace Kernel
|
|
@ -0,0 +1,155 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||||
|
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
namespace {
|
||||||
|
static const s64 DefaultTimeout =
|
||||||
|
Core::Timing::msToCycles(std::chrono::milliseconds{10000}); // 10 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
|
||||||
|
: Object{kernel}, m_lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
|
||||||
|
KResourceLimit::~KResourceLimit() = default;
|
||||||
|
|
||||||
|
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
s64 value{};
|
||||||
|
{
|
||||||
|
KScopedLightLock lk{m_lock};
|
||||||
|
value = limit_values[index];
|
||||||
|
ASSERT(value >= 0);
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
s64 value{};
|
||||||
|
{
|
||||||
|
KScopedLightLock lk{m_lock};
|
||||||
|
value = current_values[index];
|
||||||
|
ASSERT(value >= 0);
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
s64 value{};
|
||||||
|
{
|
||||||
|
KScopedLightLock lk{m_lock};
|
||||||
|
value = peak_values[index];
|
||||||
|
ASSERT(value >= 0);
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
s64 value{};
|
||||||
|
{
|
||||||
|
KScopedLightLock lk(m_lock);
|
||||||
|
ASSERT(current_values[index] >= 0);
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
value = limit_values[index] - current_values[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
KScopedLightLock lk(m_lock);
|
||||||
|
R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState);
|
||||||
|
|
||||||
|
limit_values[index] = value;
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
|
||||||
|
return Reserve(which, value, system.CoreTiming().GetClockTicks() + DefaultTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
|
||||||
|
ASSERT(value >= 0);
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
if (current_hints[index] >= limit_values[index]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop until we reserve or run out of time. */
|
||||||
|
while (true) {
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
|
||||||
|
/* If we would overflow, don't allow to succeed. */
|
||||||
|
if (current_values[index] + value <= current_values[index]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_values[index] + value <= limit_values[index]) {
|
||||||
|
current_values[index] += value;
|
||||||
|
current_hints[index] += value;
|
||||||
|
peak_values[index] = std::max(peak_values[index], current_values[index]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_hints[index] + value <= limit_values[index] &&
|
||||||
|
(timeout < 0 || system.CoreTiming().GetClockTicks() < static_cast<u64>(timeout))) {
|
||||||
|
waiter_count++;
|
||||||
|
cond_var.Wait(&m_lock, timeout);
|
||||||
|
waiter_count--;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KResourceLimit::Release(LimitableResource which, s64 value) {
|
||||||
|
Release(which, value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
|
||||||
|
ASSERT(value >= 0);
|
||||||
|
ASSERT(hint >= 0);
|
||||||
|
|
||||||
|
const auto index = static_cast<std::size_t>(which);
|
||||||
|
KScopedLightLock lk(m_lock);
|
||||||
|
ASSERT(current_values[index] <= limit_values[index]);
|
||||||
|
ASSERT(current_hints[index] <= current_values[index]);
|
||||||
|
ASSERT(value <= current_values[index]);
|
||||||
|
ASSERT(hint <= current_hints[index]);
|
||||||
|
|
||||||
|
current_values[index] -= value;
|
||||||
|
current_hints[index] -= hint;
|
||||||
|
|
||||||
|
if (waiter_count != 0) {
|
||||||
|
cond_var.Broadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||||
|
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/k_light_condition_variable.h"
|
||||||
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
|
union ResultCode;
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KernelCore;
|
||||||
|
enum class LimitableResource : u32 {
|
||||||
|
PhysicalMemoryMax = 0,
|
||||||
|
ThreadCountMax = 1,
|
||||||
|
EventCountMax = 2,
|
||||||
|
TransferMemoryCountMax = 3,
|
||||||
|
SessionCountMax = 4,
|
||||||
|
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool IsValidResourceType(LimitableResource type) {
|
||||||
|
return type < LimitableResource::Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
class KResourceLimit final : public Object {
|
||||||
|
public:
|
||||||
|
KResourceLimit(KernelCore& kernel, Core::System& system);
|
||||||
|
~KResourceLimit();
|
||||||
|
|
||||||
|
s64 GetLimitValue(LimitableResource which) const;
|
||||||
|
s64 GetCurrentValue(LimitableResource which) const;
|
||||||
|
s64 GetPeakValue(LimitableResource which) const;
|
||||||
|
s64 GetFreeValue(LimitableResource which) const;
|
||||||
|
|
||||||
|
ResultCode SetLimitValue(LimitableResource which, s64 value);
|
||||||
|
|
||||||
|
bool Reserve(LimitableResource which, s64 value);
|
||||||
|
bool Reserve(LimitableResource which, s64 value, s64 timeout);
|
||||||
|
void Release(LimitableResource which, s64 value);
|
||||||
|
void Release(LimitableResource which, s64 value, s64 hint);
|
||||||
|
|
||||||
|
std::string GetTypeName() const override {
|
||||||
|
return "KResourceLimit";
|
||||||
|
}
|
||||||
|
std::string GetName() const override {
|
||||||
|
return GetTypeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||||
|
HandleType GetHandleType() const override {
|
||||||
|
return HANDLE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Finalize() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> limit_values{};
|
||||||
|
std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_values{};
|
||||||
|
std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> current_hints{};
|
||||||
|
std::array<s64, static_cast<std::size_t>(LimitableResource::Count)> peak_values{};
|
||||||
|
mutable KLightLock m_lock;
|
||||||
|
s32 waiter_count{};
|
||||||
|
KLightConditionVariable cond_var;
|
||||||
|
KernelCore& kernel;
|
||||||
|
Core::System& system;
|
||||||
|
};
|
||||||
|
} // namespace Kernel
|
|
@ -21,6 +21,7 @@
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_condition_variable.h"
|
#include "core/hle/kernel/k_condition_variable.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
@ -29,7 +30,6 @@
|
||||||
#include "core/hle/kernel/memory/memory_layout.h"
|
#include "core/hle/kernel/memory/memory_layout.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
@ -247,7 +247,7 @@ void KThread::Finalize() {
|
||||||
// Decrement the parent process's thread count.
|
// Decrement the parent process's thread count.
|
||||||
if (parent != nullptr) {
|
if (parent != nullptr) {
|
||||||
parent->DecrementThreadCount();
|
parent->DecrementThreadCount();
|
||||||
parent->GetResourceLimit()->Release(ResourceType::Threads, 1);
|
parent->GetResourceLimit()->Release(LimitableResource::ThreadCountMax, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
#include "core/hle/kernel/memory/slab_heap.h"
|
#include "core/hle/kernel/memory/slab_heap.h"
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/hle/kernel/service_thread.h"
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
@ -66,7 +66,7 @@ struct KernelCore::Impl {
|
||||||
is_phantom_mode_for_singlecore = false;
|
is_phantom_mode_for_singlecore = false;
|
||||||
|
|
||||||
InitializePhysicalCores();
|
InitializePhysicalCores();
|
||||||
InitializeSystemResourceLimit(kernel);
|
InitializeSystemResourceLimit(kernel, system);
|
||||||
InitializeMemoryLayout();
|
InitializeMemoryLayout();
|
||||||
InitializePreemption(kernel);
|
InitializePreemption(kernel);
|
||||||
InitializeSchedulers();
|
InitializeSchedulers();
|
||||||
|
@ -131,19 +131,23 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the default system resource limit
|
// Creates the default system resource limit
|
||||||
void InitializeSystemResourceLimit(KernelCore& kernel) {
|
void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
|
||||||
system_resource_limit = ResourceLimit::Create(kernel);
|
system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||||
|
|
||||||
// If setting the default system values fails, then something seriously wrong has occurred.
|
// If setting the default system values fails, then something seriously wrong has occurred.
|
||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000)
|
ASSERT(
|
||||||
|
system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, 0x100000000)
|
||||||
|
.IsSuccess());
|
||||||
|
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800)
|
||||||
|
.IsSuccess());
|
||||||
|
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700)
|
||||||
|
.IsSuccess());
|
||||||
|
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200)
|
||||||
|
.IsSuccess());
|
||||||
|
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 900)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
|
|
||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
|
|
||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
|
|
||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
|
|
||||||
|
|
||||||
if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) ||
|
if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, 0x60000)) {
|
||||||
!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) {
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +324,7 @@ struct KernelCore::Impl {
|
||||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||||
Kernel::TimeManager time_manager;
|
Kernel::TimeManager time_manager;
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> system_resource_limit;
|
std::shared_ptr<KResourceLimit> system_resource_limit;
|
||||||
|
|
||||||
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
||||||
|
|
||||||
|
@ -390,7 +394,7 @@ void KernelCore::Shutdown() {
|
||||||
impl->Shutdown();
|
impl->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
|
std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
|
||||||
return impl->system_resource_limit;
|
return impl->system_resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class GlobalSchedulerContext;
|
||||||
class HandleTable;
|
class HandleTable;
|
||||||
class PhysicalCore;
|
class PhysicalCore;
|
||||||
class Process;
|
class Process;
|
||||||
class ResourceLimit;
|
class KResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
class ServiceThread;
|
class ServiceThread;
|
||||||
|
@ -85,7 +85,7 @@ public:
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/// Retrieves a shared pointer to the system resource limit instance.
|
/// Retrieves a shared pointer to the system resource limit instance.
|
||||||
std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
|
std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
|
||||||
|
|
||||||
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||||
std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/memory/address_space_info.h"
|
#include "core/hle/kernel/memory/address_space_info.h"
|
||||||
#include "core/hle/kernel/memory/memory_block.h"
|
#include "core/hle/kernel/memory/memory_block.h"
|
||||||
|
@ -15,7 +16,6 @@
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/memory/system_control.h"
|
#include "core/hle/kernel/memory/system_control.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Kernel::Memory {
|
namespace Kernel::Memory {
|
||||||
|
@ -413,8 +413,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
const std::size_t remaining_size{size - mapped_size};
|
const std::size_t remaining_size{size - mapped_size};
|
||||||
const std::size_t remaining_pages{remaining_size / PageSize};
|
const std::size_t remaining_pages{remaining_size / PageSize};
|
||||||
|
|
||||||
if (process->GetResourceLimit() &&
|
if (process->GetResourceLimit() && !process->GetResourceLimit()->Reserve(
|
||||||
!process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) {
|
LimitableResource::PhysicalMemoryMax, remaining_size)) {
|
||||||
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +422,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
{
|
{
|
||||||
auto block_guard = detail::ScopeExit([&] {
|
auto block_guard = detail::ScopeExit([&] {
|
||||||
system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
|
system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
|
||||||
process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size);
|
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax,
|
||||||
|
remaining_size);
|
||||||
});
|
});
|
||||||
|
|
||||||
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
|
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
|
||||||
|
@ -474,7 +475,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
CASCADE_CODE(UnmapMemory(addr, size));
|
CASCADE_CODE(UnmapMemory(addr, size));
|
||||||
|
|
||||||
auto process{system.Kernel().CurrentProcess()};
|
auto process{system.Kernel().CurrentProcess()};
|
||||||
process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size);
|
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, mapped_size);
|
||||||
physical_memory_usage -= mapped_size;
|
physical_memory_usage -= mapped_size;
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -783,7 +784,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
|
||||||
|
|
||||||
auto process{system.Kernel().CurrentProcess()};
|
auto process{system.Kernel().CurrentProcess()};
|
||||||
if (process->GetResourceLimit() && delta != 0 &&
|
if (process->GetResourceLimit() && delta != 0 &&
|
||||||
!process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) {
|
!process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, delta)) {
|
||||||
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -22,7 +23,6 @@
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/memory/slab_heap.h"
|
#include "core/hle/kernel/memory/slab_heap.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -116,7 +116,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||||
|
|
||||||
std::shared_ptr<Process> process = std::make_shared<Process>(system);
|
std::shared_ptr<Process> process = std::make_shared<Process>(system);
|
||||||
process->name = std::move(name);
|
process->name = std::move(name);
|
||||||
process->resource_limit = ResourceLimit::Create(kernel);
|
process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||||
process->status = ProcessStatus::Created;
|
process->status = ProcessStatus::Created;
|
||||||
process->program_id = 0;
|
process->program_id = 0;
|
||||||
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
|
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
|
||||||
|
@ -132,7 +132,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
|
std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
|
||||||
return resource_limit;
|
return resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ void Process::DecrementThreadCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
||||||
const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
|
const u64 capacity{resource_limit->GetCurrentValue(LimitableResource::PhysicalMemoryMax) +
|
||||||
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
||||||
main_thread_stack_size};
|
main_thread_stack_size};
|
||||||
|
|
||||||
|
@ -308,13 +308,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||||
|
|
||||||
// Set initial resource limits
|
// Set initial resource limits
|
||||||
resource_limit->SetLimitValue(
|
resource_limit->SetLimitValue(
|
||||||
ResourceType::PhysicalMemory,
|
LimitableResource::PhysicalMemoryMax,
|
||||||
kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
|
kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
|
||||||
resource_limit->SetLimitValue(ResourceType::Threads, 608);
|
resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 608);
|
||||||
resource_limit->SetLimitValue(ResourceType::Events, 700);
|
resource_limit->SetLimitValue(LimitableResource::EventCountMax, 700);
|
||||||
resource_limit->SetLimitValue(ResourceType::TransferMemory, 128);
|
resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 128);
|
||||||
resource_limit->SetLimitValue(ResourceType::Sessions, 894);
|
resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 894);
|
||||||
ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size));
|
ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, code_size));
|
||||||
|
|
||||||
// Create TLS region
|
// Create TLS region
|
||||||
tls_region_address = CreateTLSRegion();
|
tls_region_address = CreateTLSRegion();
|
||||||
|
@ -331,8 +331,8 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
|
||||||
ChangeStatus(ProcessStatus::Running);
|
ChangeStatus(ProcessStatus::Running);
|
||||||
|
|
||||||
SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
|
SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
|
||||||
resource_limit->Reserve(ResourceType::Threads, 1);
|
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
|
||||||
resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size);
|
resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::PrepareForTermination() {
|
void Process::PrepareForTermination() {
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ProgramMetadata;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class ResourceLimit;
|
class KResourceLimit;
|
||||||
class KThread;
|
class KThread;
|
||||||
class TLSPage;
|
class TLSPage;
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the resource limit descriptor for this process
|
/// Gets the resource limit descriptor for this process
|
||||||
std::shared_ptr<ResourceLimit> GetResourceLimit() const;
|
std::shared_ptr<KResourceLimit> GetResourceLimit() const;
|
||||||
|
|
||||||
/// Gets the ideal CPU core ID for this process
|
/// Gets the ideal CPU core ID for this process
|
||||||
u8 GetIdealCoreId() const {
|
u8 GetIdealCoreId() const {
|
||||||
|
@ -402,7 +402,7 @@ private:
|
||||||
u32 system_resource_size = 0;
|
u32 system_resource_size = 0;
|
||||||
|
|
||||||
/// Resource limit descriptor for this process
|
/// Resource limit descriptor for this process
|
||||||
std::shared_ptr<ResourceLimit> resource_limit;
|
std::shared_ptr<KResourceLimit> resource_limit;
|
||||||
|
|
||||||
/// The ideal CPU core for this process, threads are scheduled on this core by default.
|
/// The ideal CPU core for this process, threads are scheduled on this core by default.
|
||||||
u8 ideal_core = 0;
|
u8 ideal_core = 0;
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Copyright 2015 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include "core/hle/kernel/errors.h"
|
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/hle/result.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
namespace {
|
|
||||||
constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
|
|
||||||
return static_cast<std::size_t>(type);
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
|
|
||||||
ResourceLimit::~ResourceLimit() = default;
|
|
||||||
|
|
||||||
bool ResourceLimit::Reserve(ResourceType resource, s64 amount) {
|
|
||||||
return Reserve(resource, amount, 10000000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) {
|
|
||||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
|
||||||
|
|
||||||
s64 new_value = current[index] + amount;
|
|
||||||
if (new_value > limit[index] && available[index] + amount <= limit[index]) {
|
|
||||||
// TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout
|
|
||||||
new_value = current[index] + amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_value <= limit[index]) {
|
|
||||||
current[index] = new_value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceLimit::Release(ResourceType resource, u64 amount) {
|
|
||||||
Release(resource, amount, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) {
|
|
||||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
|
||||||
|
|
||||||
current[index] -= used_amount;
|
|
||||||
available[index] -= available_amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
|
|
||||||
return std::make_shared<ResourceLimit>(kernel);
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
|
|
||||||
return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource));
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
|
|
||||||
return limit.at(ResourceTypeToIndex(resource));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
|
|
||||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
|
||||||
if (current[index] <= value) {
|
|
||||||
limit[index] = value;
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource,
|
|
||||||
value, index);
|
|
||||||
return ERR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace Kernel
|
|
|
@ -1,106 +0,0 @@
|
||||||
// Copyright 2015 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "core/hle/kernel/object.h"
|
|
||||||
|
|
||||||
union ResultCode;
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
class KernelCore;
|
|
||||||
|
|
||||||
enum class ResourceType : u32 {
|
|
||||||
PhysicalMemory,
|
|
||||||
Threads,
|
|
||||||
Events,
|
|
||||||
TransferMemory,
|
|
||||||
Sessions,
|
|
||||||
|
|
||||||
// Used as a count, not an actual type.
|
|
||||||
ResourceTypeCount
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr bool IsValidResourceType(ResourceType type) {
|
|
||||||
return type < ResourceType::ResourceTypeCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResourceLimit final : public Object {
|
|
||||||
public:
|
|
||||||
explicit ResourceLimit(KernelCore& kernel);
|
|
||||||
~ResourceLimit() override;
|
|
||||||
|
|
||||||
/// Creates a resource limit object.
|
|
||||||
static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel);
|
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
|
||||||
return "ResourceLimit";
|
|
||||||
}
|
|
||||||
std::string GetName() const override {
|
|
||||||
return GetTypeName();
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
|
||||||
HandleType GetHandleType() const override {
|
|
||||||
return HANDLE_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reserve(ResourceType resource, s64 amount);
|
|
||||||
bool Reserve(ResourceType resource, s64 amount, u64 timeout);
|
|
||||||
void Release(ResourceType resource, u64 amount);
|
|
||||||
void Release(ResourceType resource, u64 used_amount, u64 available_amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current value for the specified resource.
|
|
||||||
* @param resource Requested resource type
|
|
||||||
* @returns The current value of the resource type
|
|
||||||
*/
|
|
||||||
s64 GetCurrentResourceValue(ResourceType resource) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the max value for the specified resource.
|
|
||||||
* @param resource Requested resource type
|
|
||||||
* @returns The max value of the resource type
|
|
||||||
*/
|
|
||||||
s64 GetMaxResourceValue(ResourceType resource) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the limit value for a given resource type.
|
|
||||||
*
|
|
||||||
* @param resource The resource type to apply the limit to.
|
|
||||||
* @param value The limit to apply to the given resource type.
|
|
||||||
*
|
|
||||||
* @return A result code indicating if setting the limit value
|
|
||||||
* was successful or not.
|
|
||||||
*
|
|
||||||
* @note The supplied limit value *must* be greater than or equal to
|
|
||||||
* the current resource value for the given resource type,
|
|
||||||
* otherwise ERR_INVALID_STATE will be returned.
|
|
||||||
*/
|
|
||||||
ResultCode SetLimitValue(ResourceType resource, s64 value);
|
|
||||||
|
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
|
|
||||||
// functions
|
|
||||||
//
|
|
||||||
// Currently we have no way of distinguishing if a Create was called by the running application,
|
|
||||||
// or by a service module. Approach this once we have separated the service modules into their
|
|
||||||
// own processes
|
|
||||||
|
|
||||||
using ResourceArray =
|
|
||||||
std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
|
|
||||||
|
|
||||||
ResourceArray limit{};
|
|
||||||
ResourceArray current{};
|
|
||||||
ResourceArray available{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_condition_variable.h"
|
#include "core/hle/kernel/k_condition_variable.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
|
@ -37,7 +38,6 @@
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
@ -141,7 +141,7 @@ enum class ResourceLimitValueType {
|
||||||
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
|
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
|
||||||
u32 resource_type, ResourceLimitValueType value_type) {
|
u32 resource_type, ResourceLimitValueType value_type) {
|
||||||
std::lock_guard lock{HLE::g_hle_lock};
|
std::lock_guard lock{HLE::g_hle_lock};
|
||||||
const auto type = static_cast<ResourceType>(resource_type);
|
const auto type = static_cast<LimitableResource>(resource_type);
|
||||||
if (!IsValidResourceType(type)) {
|
if (!IsValidResourceType(type)) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
||||||
return ERR_INVALID_ENUM_VALUE;
|
return ERR_INVALID_ENUM_VALUE;
|
||||||
|
@ -151,7 +151,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
||||||
ASSERT(current_process != nullptr);
|
ASSERT(current_process != nullptr);
|
||||||
|
|
||||||
const auto resource_limit_object =
|
const auto resource_limit_object =
|
||||||
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
|
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
||||||
if (!resource_limit_object) {
|
if (!resource_limit_object) {
|
||||||
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
||||||
resource_limit);
|
resource_limit);
|
||||||
|
@ -159,10 +159,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_type == ResourceLimitValueType::CurrentValue) {
|
if (value_type == ResourceLimitValueType::CurrentValue) {
|
||||||
return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
|
return MakeResult(resource_limit_object->GetCurrentValue(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult(resource_limit_object->GetMaxResourceValue(type));
|
return MakeResult(resource_limit_object->GetLimitValue(type));
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
@ -312,7 +312,8 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
|
||||||
return ERR_NOT_FOUND;
|
return ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1));
|
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::SessionCountMax,
|
||||||
|
1));
|
||||||
|
|
||||||
auto client_port = it->second;
|
auto client_port = it->second;
|
||||||
|
|
||||||
|
@ -1450,7 +1451,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
|
||||||
Svc::ResultInvalidPriority);
|
Svc::ResultInvalidPriority);
|
||||||
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
|
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
|
||||||
|
|
||||||
ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
ASSERT(process.GetResourceLimit()->Reserve(
|
||||||
|
LimitableResource::ThreadCountMax, 1,
|
||||||
|
system.CoreTiming().GetClockTicks() +
|
||||||
|
Core::Timing::msToCycles(std::chrono::milliseconds{100})));
|
||||||
|
|
||||||
std::shared_ptr<KThread> thread;
|
std::shared_ptr<KThread> thread;
|
||||||
{
|
{
|
||||||
|
@ -1972,7 +1976,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle)
|
||||||
LOG_DEBUG(Kernel_SVC, "called");
|
LOG_DEBUG(Kernel_SVC, "called");
|
||||||
|
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
auto resource_limit = ResourceLimit::Create(kernel);
|
auto resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||||
|
|
||||||
auto* const current_process = kernel.CurrentProcess();
|
auto* const current_process = kernel.CurrentProcess();
|
||||||
ASSERT(current_process != nullptr);
|
ASSERT(current_process != nullptr);
|
||||||
|
@ -2019,7 +2023,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||||
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
|
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
|
||||||
resource_type, value);
|
resource_type, value);
|
||||||
|
|
||||||
const auto type = static_cast<ResourceType>(resource_type);
|
const auto type = static_cast<LimitableResource>(resource_type);
|
||||||
if (!IsValidResourceType(type)) {
|
if (!IsValidResourceType(type)) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
||||||
return ERR_INVALID_ENUM_VALUE;
|
return ERR_INVALID_ENUM_VALUE;
|
||||||
|
@ -2029,7 +2033,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||||
ASSERT(current_process != nullptr);
|
ASSERT(current_process != nullptr);
|
||||||
|
|
||||||
auto resource_limit_object =
|
auto resource_limit_object =
|
||||||
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
|
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
||||||
if (!resource_limit_object) {
|
if (!resource_limit_object) {
|
||||||
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
||||||
resource_limit);
|
resource_limit);
|
||||||
|
@ -2041,8 +2045,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
Kernel_SVC,
|
Kernel_SVC,
|
||||||
"Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
|
"Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
|
||||||
resource_limit_object->GetMaxResourceValue(type), resource_type,
|
resource_limit_object->GetLimitValue(type), resource_type,
|
||||||
resource_limit_object->GetCurrentResourceValue(type));
|
resource_limit_object->GetCurrentValue(type));
|
||||||
return set_result;
|
return set_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue