From 3be1a565f895d5399a6c1f6d0997dc528537fe86 Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Sat, 30 Jan 2021 20:40:49 +1100 Subject: kernel: Rewrite resource limit to be more accurate Matches closer to hardware --- src/core/hle/kernel/k_resource_limit.cpp | 155 +++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/core/hle/kernel/k_resource_limit.cpp (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp new file mode 100644 index 000000000..f943d6562 --- /dev/null +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -0,0 +1,155 @@ +// 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(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(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(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(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(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(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(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(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 -- cgit v1.2.3 From 3bf62c7a8a68822e608c2f5f5748bd111d7ee4cf Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Sat, 30 Jan 2021 21:03:10 +1100 Subject: Move to GetGlobalTimeNs, fix GetTotalPhysicalMemoryAvailable --- src/core/hle/kernel/k_resource_limit.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index f943d6562..b3076b030 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -14,8 +14,7 @@ namespace Kernel { namespace { -static const s64 DefaultTimeout = - Core::Timing::msToCycles(std::chrono::milliseconds{10000}); // 10 seconds +constexpr s64 DefaultTimeout = 10000000000; // 10 seconds } KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) @@ -86,7 +85,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { } bool KResourceLimit::Reserve(LimitableResource which, s64 value) { - return Reserve(which, value, system.CoreTiming().GetClockTicks() + DefaultTimeout); + return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout); } bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { @@ -117,7 +116,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { } if (current_hints[index] + value <= limit_values[index] && - (timeout < 0 || system.CoreTiming().GetClockTicks() < static_cast(timeout))) { + (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) { waiter_count++; cond_var.Wait(&m_lock, timeout); waiter_count--; -- cgit v1.2.3 From 7791cfd9603d983fe58d3463e94d87448ad9e5a6 Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Sat, 30 Jan 2021 21:19:49 +1100 Subject: Drop m_ from lock --- src/core/hle/kernel/k_resource_limit.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index b3076b030..65c30e9b3 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -18,14 +18,14 @@ constexpr s64 DefaultTimeout = 10000000000; // 10 seconds } KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) - : Object{kernel}, m_lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} + : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} KResourceLimit::~KResourceLimit() = default; s64 KResourceLimit::GetLimitValue(LimitableResource which) const { const auto index = static_cast(which); s64 value{}; { - KScopedLightLock lk{m_lock}; + KScopedLightLock lk{lock}; value = limit_values[index]; ASSERT(value >= 0); ASSERT(current_values[index] <= limit_values[index]); @@ -51,7 +51,7 @@ s64 KResourceLimit::GetPeakValue(LimitableResource which) const { const auto index = static_cast(which); s64 value{}; { - KScopedLightLock lk{m_lock}; + KScopedLightLock lk{lock}; value = peak_values[index]; ASSERT(value >= 0); ASSERT(current_values[index] <= limit_values[index]); @@ -64,7 +64,7 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const { const auto index = static_cast(which); s64 value{}; { - KScopedLightLock lk(m_lock); + KScopedLightLock lk(lock); ASSERT(current_values[index] >= 0); ASSERT(current_values[index] <= limit_values[index]); ASSERT(current_hints[index] <= current_values[index]); @@ -76,7 +76,7 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const { ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { const auto index = static_cast(which); - KScopedLightLock lk(m_lock); + KScopedLightLock lk(lock); R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState); limit_values[index] = value; @@ -91,7 +91,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value) { bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { ASSERT(value >= 0); const auto index = static_cast(which); - KScopedLightLock lk(m_lock); + KScopedLightLock lk(lock); ASSERT(current_hints[index] <= current_values[index]); if (current_hints[index] >= limit_values[index]) { @@ -118,7 +118,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { if (current_hints[index] + value <= limit_values[index] && (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) { waiter_count++; - cond_var.Wait(&m_lock, timeout); + cond_var.Wait(&lock, timeout); waiter_count--; } else { break; @@ -137,7 +137,7 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) { ASSERT(hint >= 0); const auto index = static_cast(which); - KScopedLightLock lk(m_lock); + KScopedLightLock lk(lock); ASSERT(current_values[index] <= limit_values[index]); ASSERT(current_hints[index] <= current_values[index]); ASSERT(value <= current_values[index]); -- cgit v1.2.3 From 56742c6222b7185b43a3463955c58a142ed33c1e Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Sat, 30 Jan 2021 21:20:35 +1100 Subject: cleanup commenting --- src/core/hle/kernel/k_resource_limit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index 65c30e9b3..1bcc390ff 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -98,12 +98,12 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { return false; } - /* Loop until we reserve or run out of time. */ + // 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 we would overflow, don't allow to succeed. if (current_values[index] + value <= current_values[index]) { break; } -- cgit v1.2.3 From ee333e063d9de4b36ccbc0c5b7b3e323bff9eda3 Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Sat, 30 Jan 2021 21:51:22 +1100 Subject: fix compile error --- src/core/hle/kernel/k_resource_limit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index 1bcc390ff..3cee8d0f7 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -38,7 +38,7 @@ s64 KResourceLimit::GetCurrentValue(LimitableResource which) const { const auto index = static_cast(which); s64 value{}; { - KScopedLightLock lk{m_lock}; + KScopedLightLock lk{lock}; value = current_values[index]; ASSERT(value >= 0); ASSERT(current_values[index] <= limit_values[index]); -- cgit v1.2.3 From 9e4b2d60bc4827552b0d74675ae03fec06f73452 Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Tue, 2 Feb 2021 13:23:00 +1100 Subject: Address issues --- src/core/hle/kernel/k_resource_limit.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/core/hle/kernel/k_resource_limit.cpp') diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index 3cee8d0f7..ab2ab683f 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -13,9 +13,7 @@ #include "core/hle/kernel/svc_results.h" namespace Kernel { -namespace { constexpr s64 DefaultTimeout = 10000000000; // 10 seconds -} KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} -- cgit v1.2.3