From 5fa6b15215d2c15a1601c88ac1125a28c55797fc Mon Sep 17 00:00:00 2001 From: ameerj Date: Thu, 4 Feb 2021 20:06:54 -0500 Subject: kernel: KScopedReservation implementation This implements KScopedReservation, allowing resource limit reservations to be more HW accurate, and release upon failure without requiring too many conditionals. --- src/core/hle/kernel/svc.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/svc.cpp') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ef3c7ac5..1d377ffe6 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -30,6 +30,7 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.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_thread.h" @@ -1516,8 +1517,13 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return ResultInvalidPriority; } - ASSERT(process.GetResourceLimit()->Reserve( - LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); + KScopedResourceReservation thread_reservation( + kernel.CurrentProcess(), LimitableResource::Threads, 1, + system.CoreTiming().GetGlobalTimeNs().count() + 100000000); + if (!thread_reservation.Succeeded()) { + LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); + return ERR_RESOURCE_LIMIT_EXCEEDED; + } std::shared_ptr thread; { @@ -1537,6 +1543,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e // Set the thread name for debugging purposes. thread->SetName( fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); + thread_reservation.Commit(); return RESULT_SUCCESS; } @@ -1884,6 +1891,13 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd } auto& kernel = system.Kernel(); + // Reserve a new transfer memory from the process resource limit. + KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), + LimitableResource::TransferMemory); + if (!trmem_reservation.Succeeded()) { + LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); + return ERR_RESOURCE_LIMIT_EXCEEDED; + } auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { @@ -1895,6 +1909,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd if (result.Failed()) { return result.Code(); } + trmem_reservation.Commit(); *handle = *result; return RESULT_SUCCESS; @@ -2002,8 +2017,17 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle static ResultCode SignalEvent(Core::System& system, Handle event_handle) { LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); + auto& kernel = system.Kernel(); // Get the current handle table. - const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Reserve a new event from the process resource limit. + KScopedResourceReservation event_reservation(kernel.CurrentProcess(), + LimitableResource::Events); + if (!event_reservation.Succeeded()) { + LOG_ERROR(Kernel, "Could not reserve a new event"); + return ERR_RESOURCE_LIMIT_EXCEEDED; + } // Get the writable event. auto writable_event = handle_table.Get(event_handle); @@ -2012,6 +2036,9 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { return ResultInvalidHandle; } + // Commit the successfuly reservation. + event_reservation.Commit(); + return writable_event->Signal(); } -- cgit v1.2.3 From ec9b6641b12aa04ae3d7782b0423037dbc1400ac Mon Sep 17 00:00:00 2001 From: ameerj Date: Fri, 12 Feb 2021 19:05:24 -0500 Subject: kernel: More accurately reserve and release resources --- src/core/hle/kernel/svc.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel/svc.cpp') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1d377ffe6..31d899e06 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -138,6 +138,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds enum class ResourceLimitValueType { CurrentValue, LimitValue, + PeakValue, }; ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, @@ -160,11 +161,17 @@ ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_ return ResultInvalidHandle; } - if (value_type == ResourceLimitValueType::CurrentValue) { + switch (value_type) { + case ResourceLimitValueType::CurrentValue: return MakeResult(resource_limit_object->GetCurrentValue(type)); + case ResourceLimitValueType::LimitValue: + return MakeResult(resource_limit_object->GetLimitValue(type)); + case ResourceLimitValueType::PeakValue: + return MakeResult(resource_limit_object->GetPeakValue(type)); + default: + LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type); + return ResultInvalidEnumValue; } - - return MakeResult(resource_limit_object->GetLimitValue(type)); } } // Anonymous namespace @@ -314,8 +321,6 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, return ResultNotFound; } - ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1)); - auto client_port = it->second; std::shared_ptr client_session; @@ -1522,7 +1527,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e system.CoreTiming().GetGlobalTimeNs().count() + 100000000); if (!thread_reservation.Succeeded()) { LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); - return ERR_RESOURCE_LIMIT_EXCEEDED; + return ResultResourceLimitedExceeded; } std::shared_ptr thread; @@ -1896,7 +1901,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd LimitableResource::TransferMemory); if (!trmem_reservation.Succeeded()) { LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); - return ERR_RESOURCE_LIMIT_EXCEEDED; + return ResultResourceLimitedExceeded; } auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); @@ -2026,7 +2031,7 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { LimitableResource::Events); if (!event_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve a new event"); - return ERR_RESOURCE_LIMIT_EXCEEDED; + return ResultResourceLimitedExceeded; } // Get the writable event. -- cgit v1.2.3