kernel: KScopedReservation implementation

This implements KScopedReservation, allowing resource limit reservations to be more HW accurate, and release upon failure without requiring too many conditionals.
This commit is contained in:
ameerj 2021-02-04 20:06:54 -05:00
parent 37939482fb
commit 5fa6b15215
6 changed files with 152 additions and 26 deletions

View file

@ -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<KThread> 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<KWritableEvent>(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();
}