summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ameerj2021-02-04 20:06:54 -0500
committerGravatar ameerj2021-02-12 18:57:34 -0500
commit5fa6b15215d2c15a1601c88ac1125a28c55797fc (patch)
tree4a25c58180aecd1eb9bcc3560a1a3dfa18c67761 /src
parentkernel: Unify result codes (#5890) (diff)
downloadyuzu-5fa6b15215d2c15a1601c88ac1125a28c55797fc.tar.gz
yuzu-5fa6b15215d2c15a1601c88ac1125a28c55797fc.tar.xz
yuzu-5fa6b15215d2c15a1601c88ac1125a28c55797fc.zip
kernel: KScopedReservation implementation
This implements KScopedReservation, allowing resource limit reservations to be more HW accurate, and release upon failure without requiring too many conditionals.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/k_scoped_resource_reservation.h67
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp37
-rw-r--r--src/core/hle/kernel/process.cpp33
-rw-r--r--src/core/hle/kernel/shared_memory.cpp7
-rw-r--r--src/core/hle/kernel/svc.cpp33
6 files changed, 152 insertions, 26 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 52151e788..1662ec63d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -174,6 +174,7 @@ add_library(core STATIC
174 hle/kernel/k_scheduler.h 174 hle/kernel/k_scheduler.h
175 hle/kernel/k_scheduler_lock.h 175 hle/kernel/k_scheduler_lock.h
176 hle/kernel/k_scoped_lock.h 176 hle/kernel/k_scoped_lock.h
177 hle/kernel/k_scoped_resource_reservation.h
177 hle/kernel/k_scoped_scheduler_lock_and_sleep.h 178 hle/kernel/k_scoped_scheduler_lock_and_sleep.h
178 hle/kernel/k_synchronization_object.cpp 179 hle/kernel/k_synchronization_object.cpp
179 hle/kernel/k_synchronization_object.h 180 hle/kernel/k_synchronization_object.h
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h
new file mode 100644
index 000000000..c5deca00b
--- /dev/null
+++ b/src/core/hle/kernel/k_scoped_resource_reservation.h
@@ -0,0 +1,67 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/common_types.h"
11#include "core/hle/kernel/k_resource_limit.h"
12#include "core/hle/kernel/process.h"
13
14namespace Kernel {
15
16class KScopedResourceReservation {
17public:
18 explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
19 s64 v, s64 timeout)
20 : resource_limit(std::move(l)), value(v), resource(r) {
21 if (resource_limit && value) {
22 success = resource_limit->Reserve(resource, value, timeout);
23 } else {
24 success = true;
25 }
26 }
27
28 explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
29 s64 v = 1)
30 : resource_limit(std::move(l)), value(v), resource(r) {
31 if (resource_limit && value) {
32 success = resource_limit->Reserve(resource, value);
33 } else {
34 success = true;
35 }
36 }
37
38 explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t)
39 : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {}
40
41 explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1)
42 : KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
43
44 ~KScopedResourceReservation() noexcept {
45 if (resource_limit && value && success) {
46 // resource was not committed, release the reservation.
47 resource_limit->Release(resource, value);
48 }
49 }
50
51 /// Commit the resource reservation, destruction of this object does not release the resource
52 void Commit() {
53 resource_limit = nullptr;
54 }
55
56 [[nodiscard]] bool Succeeded() const {
57 return success;
58 }
59
60private:
61 std::shared_ptr<KResourceLimit> resource_limit;
62 s64 value;
63 LimitableResource resource;
64 bool success;
65};
66
67} // namespace Kernel
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index 5947fc748..00ed9b881 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -6,7 +6,7 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/scope_exit.h" 7#include "common/scope_exit.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/k_resource_limit.h" 9#include "core/hle/kernel/k_scoped_resource_reservation.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory/address_space_info.h" 11#include "core/hle/kernel/memory/address_space_info.h"
12#include "core/hle/kernel/memory/memory_block.h" 12#include "core/hle/kernel/memory/memory_block.h"
@@ -409,27 +409,25 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
409 return RESULT_SUCCESS; 409 return RESULT_SUCCESS;
410 } 410 }
411 411
412 auto process{system.Kernel().CurrentProcess()};
413 const std::size_t remaining_size{size - mapped_size}; 412 const std::size_t remaining_size{size - mapped_size};
414 const std::size_t remaining_pages{remaining_size / PageSize}; 413 const std::size_t remaining_pages{remaining_size / PageSize};
415 414
416 if (process->GetResourceLimit() && 415 // Reserve the memory from the process resource limit.
417 !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) { 416 KScopedResourceReservation memory_reservation(
417 system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
418 remaining_size);
419 if (!memory_reservation.Succeeded()) {
420 LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size);
418 return ResultResourceLimitedExceeded; 421 return ResultResourceLimitedExceeded;
419 } 422 }
420 423
421 PageLinkedList page_linked_list; 424 PageLinkedList page_linked_list;
422 {
423 auto block_guard = detail::ScopeExit([&] {
424 system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
425 process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size);
426 });
427 425
428 CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, 426 CASCADE_CODE(
429 memory_pool)); 427 system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool));
430 428
431 block_guard.Cancel(); 429 // We succeeded, so commit the memory reservation.
432 } 430 memory_reservation.Commit();
433 431
434 MapPhysicalMemory(page_linked_list, addr, end_addr); 432 MapPhysicalMemory(page_linked_list, addr, end_addr);
435 433
@@ -781,9 +779,13 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
781 779
782 const u64 delta{size - previous_heap_size}; 780 const u64 delta{size - previous_heap_size};
783 781
784 auto process{system.Kernel().CurrentProcess()}; 782 // Reserve memory for the heap extension.
785 if (process->GetResourceLimit() && delta != 0 && 783 KScopedResourceReservation memory_reservation(
786 !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) { 784 system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
785 delta);
786
787 if (!memory_reservation.Succeeded()) {
788 LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta);
787 return ResultResourceLimitedExceeded; 789 return ResultResourceLimitedExceeded;
788 } 790 }
789 791
@@ -800,6 +802,9 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
800 CASCADE_CODE( 802 CASCADE_CODE(
801 Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); 803 Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup));
802 804
805 // Succeeded in allocation, commit the resource reservation
806 memory_reservation.Commit();
807
803 block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal, 808 block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal,
804 MemoryPermission::ReadAndWrite); 809 MemoryPermission::ReadAndWrite);
805 810
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 39dc3898a..05e21830c 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/code_set.h" 16#include "core/hle/kernel/code_set.h"
17#include "core/hle/kernel/k_resource_limit.h" 17#include "core/hle/kernel/k_resource_limit.h"
18#include "core/hle/kernel/k_scheduler.h" 18#include "core/hle/kernel/k_scheduler.h"
19#include "core/hle/kernel/k_scoped_resource_reservation.h"
19#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
20#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/memory/memory_block_manager.h" 22#include "core/hle/kernel/memory/memory_block_manager.h"
@@ -116,6 +117,9 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
116 117
117 std::shared_ptr<Process> process = std::make_shared<Process>(system); 118 std::shared_ptr<Process> process = std::make_shared<Process>(system);
118 process->name = std::move(name); 119 process->name = std::move(name);
120
121 // TODO: This is inaccurate
122 // The process should hold a reference to the kernel-wide resource limit.
119 process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); 123 process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
120 process->status = ProcessStatus::Created; 124 process->status = ProcessStatus::Created;
121 process->program_id = 0; 125 process->program_id = 0;
@@ -154,6 +158,9 @@ void Process::DecrementThreadCount() {
154} 158}
155 159
156u64 Process::GetTotalPhysicalMemoryAvailable() const { 160u64 Process::GetTotalPhysicalMemoryAvailable() const {
161 // TODO: This is expected to always return the application memory pool size after accurately
162 // reserving kernel resources. The current workaround uses a process-local resource limit of
163 // application memory pool size, which is inaccurate.
157 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + 164 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
158 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + 165 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
159 main_thread_stack_size}; 166 main_thread_stack_size};
@@ -263,6 +270,17 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
263 system_resource_size = metadata.GetSystemResourceSize(); 270 system_resource_size = metadata.GetSystemResourceSize();
264 image_size = code_size; 271 image_size = code_size;
265 272
273 // Set initial resource limits
274 resource_limit->SetLimitValue(
275 LimitableResource::PhysicalMemory,
276 kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
277 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
278 code_size + system_resource_size);
279 if (!memory_reservation.Succeeded()) {
280 LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
281 code_size + system_resource_size);
282 return ERR_RESOURCE_LIMIT_EXCEEDED;
283 }
266 // Initialize proces address space 284 // Initialize proces address space
267 if (const ResultCode result{ 285 if (const ResultCode result{
268 page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, 286 page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000,
@@ -304,24 +322,22 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
304 UNREACHABLE(); 322 UNREACHABLE();
305 } 323 }
306 324
307 // Set initial resource limits
308 resource_limit->SetLimitValue(
309 LimitableResource::PhysicalMemory,
310 kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
311 resource_limit->SetLimitValue(LimitableResource::Threads, 608); 325 resource_limit->SetLimitValue(LimitableResource::Threads, 608);
312 resource_limit->SetLimitValue(LimitableResource::Events, 700); 326 resource_limit->SetLimitValue(LimitableResource::Events, 700);
313 resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128); 327 resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
314 resource_limit->SetLimitValue(LimitableResource::Sessions, 894); 328 resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
315 ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size));
316 329
317 // Create TLS region 330 // Create TLS region
318 tls_region_address = CreateTLSRegion(); 331 tls_region_address = CreateTLSRegion();
332 memory_reservation.Commit();
319 333
320 return handle_table.SetSize(capabilities.GetHandleTableSize()); 334 return handle_table.SetSize(capabilities.GetHandleTableSize());
321} 335}
322 336
323void Process::Run(s32 main_thread_priority, u64 stack_size) { 337void Process::Run(s32 main_thread_priority, u64 stack_size) {
324 AllocateMainThreadStack(stack_size); 338 AllocateMainThreadStack(stack_size);
339 resource_limit->Reserve(LimitableResource::Threads, 1);
340 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
325 341
326 const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; 342 const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size};
327 ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); 343 ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError());
@@ -329,8 +345,6 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
329 ChangeStatus(ProcessStatus::Running); 345 ChangeStatus(ProcessStatus::Running);
330 346
331 SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); 347 SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
332 resource_limit->Reserve(LimitableResource::Threads, 1);
333 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
334} 348}
335 349
336void Process::PrepareForTermination() { 350void Process::PrepareForTermination() {
@@ -357,6 +371,11 @@ void Process::PrepareForTermination() {
357 FreeTLSRegion(tls_region_address); 371 FreeTLSRegion(tls_region_address);
358 tls_region_address = 0; 372 tls_region_address = 0;
359 373
374 if (resource_limit) {
375 resource_limit->Release(LimitableResource::PhysicalMemory,
376 main_thread_stack_size + image_size);
377 }
378
360 ChangeStatus(ProcessStatus::Exited); 379 ChangeStatus(ProcessStatus::Exited);
361} 380}
362 381
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 0cd467110..67d748561 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/kernel/k_scoped_resource_reservation.h"
7#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/memory/page_table.h" 9#include "core/hle/kernel/memory/page_table.h"
9#include "core/hle/kernel/shared_memory.h" 10#include "core/hle/kernel/shared_memory.h"
@@ -21,6 +22,11 @@ std::shared_ptr<SharedMemory> SharedMemory::Create(
21 Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, 22 Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size,
22 std::string name) { 23 std::string name) {
23 24
25 const auto resource_limit = kernel.GetSystemResourceLimit();
26 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
27 size);
28 ASSERT(memory_reservation.Succeeded());
29
24 std::shared_ptr<SharedMemory> shared_memory{ 30 std::shared_ptr<SharedMemory> shared_memory{
25 std::make_shared<SharedMemory>(kernel, device_memory)}; 31 std::make_shared<SharedMemory>(kernel, device_memory)};
26 32
@@ -32,6 +38,7 @@ std::shared_ptr<SharedMemory> SharedMemory::Create(
32 shared_memory->size = size; 38 shared_memory->size = size;
33 shared_memory->name = name; 39 shared_memory->name = name;
34 40
41 memory_reservation.Commit();
35 return shared_memory; 42 return shared_memory;
36} 43}
37 44
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 @@
30#include "core/hle/kernel/k_readable_event.h" 30#include "core/hle/kernel/k_readable_event.h"
31#include "core/hle/kernel/k_resource_limit.h" 31#include "core/hle/kernel/k_resource_limit.h"
32#include "core/hle/kernel/k_scheduler.h" 32#include "core/hle/kernel/k_scheduler.h"
33#include "core/hle/kernel/k_scoped_resource_reservation.h"
33#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 34#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
34#include "core/hle/kernel/k_synchronization_object.h" 35#include "core/hle/kernel/k_synchronization_object.h"
35#include "core/hle/kernel/k_thread.h" 36#include "core/hle/kernel/k_thread.h"
@@ -1516,8 +1517,13 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1516 return ResultInvalidPriority; 1517 return ResultInvalidPriority;
1517 } 1518 }
1518 1519
1519 ASSERT(process.GetResourceLimit()->Reserve( 1520 KScopedResourceReservation thread_reservation(
1520 LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); 1521 kernel.CurrentProcess(), LimitableResource::Threads, 1,
1522 system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
1523 if (!thread_reservation.Succeeded()) {
1524 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
1525 return ERR_RESOURCE_LIMIT_EXCEEDED;
1526 }
1521 1527
1522 std::shared_ptr<KThread> thread; 1528 std::shared_ptr<KThread> thread;
1523 { 1529 {
@@ -1537,6 +1543,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1537 // Set the thread name for debugging purposes. 1543 // Set the thread name for debugging purposes.
1538 thread->SetName( 1544 thread->SetName(
1539 fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); 1545 fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle));
1546 thread_reservation.Commit();
1540 1547
1541 return RESULT_SUCCESS; 1548 return RESULT_SUCCESS;
1542} 1549}
@@ -1884,6 +1891,13 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
1884 } 1891 }
1885 1892
1886 auto& kernel = system.Kernel(); 1893 auto& kernel = system.Kernel();
1894 // Reserve a new transfer memory from the process resource limit.
1895 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
1896 LimitableResource::TransferMemory);
1897 if (!trmem_reservation.Succeeded()) {
1898 LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
1899 return ERR_RESOURCE_LIMIT_EXCEEDED;
1900 }
1887 auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); 1901 auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
1888 1902
1889 if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { 1903 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
1895 if (result.Failed()) { 1909 if (result.Failed()) {
1896 return result.Code(); 1910 return result.Code();
1897 } 1911 }
1912 trmem_reservation.Commit();
1898 1913
1899 *handle = *result; 1914 *handle = *result;
1900 return RESULT_SUCCESS; 1915 return RESULT_SUCCESS;
@@ -2002,8 +2017,17 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
2002static ResultCode SignalEvent(Core::System& system, Handle event_handle) { 2017static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
2003 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); 2018 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
2004 2019
2020 auto& kernel = system.Kernel();
2005 // Get the current handle table. 2021 // Get the current handle table.
2006 const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 2022 const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
2023
2024 // Reserve a new event from the process resource limit.
2025 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2026 LimitableResource::Events);
2027 if (!event_reservation.Succeeded()) {
2028 LOG_ERROR(Kernel, "Could not reserve a new event");
2029 return ERR_RESOURCE_LIMIT_EXCEEDED;
2030 }
2007 2031
2008 // Get the writable event. 2032 // Get the writable event.
2009 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 2033 auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
@@ -2012,6 +2036,9 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
2012 return ResultInvalidHandle; 2036 return ResultInvalidHandle;
2013 } 2037 }
2014 2038
2039 // Commit the successfuly reservation.
2040 event_reservation.Commit();
2041
2015 return writable_event->Signal(); 2042 return writable_event->Signal();
2016} 2043}
2017 2044