diff options
| author | 2021-04-17 23:38:20 -0700 | |
|---|---|---|
| committer | 2021-05-05 16:40:51 -0700 | |
| commit | 674122038ad01aae7eb4b6eff604f94fb8864bd4 (patch) | |
| tree | 78553461d9351d222e82cbdc66f9672130979960 /src | |
| parent | hle: kernel: svc: Use new handle table API for Process. (diff) | |
| download | yuzu-674122038ad01aae7eb4b6eff604f94fb8864bd4.tar.gz yuzu-674122038ad01aae7eb4b6eff604f94fb8864bd4.tar.xz yuzu-674122038ad01aae7eb4b6eff604f94fb8864bd4.zip | |
hle: kernel: svc: Migrate WaitSynchronization.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/handle_table.h | 55 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 70 |
2 files changed, 78 insertions, 47 deletions
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index d57188844..d6abdcd47 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/k_auto_object.h" | 12 | #include "core/hle/kernel/k_auto_object.h" |
| 13 | #include "core/hle/kernel/k_spin_lock.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/object.h" | 15 | #include "core/hle/kernel/object.h" |
| 15 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| @@ -111,6 +112,16 @@ public: | |||
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | template <typename T = KAutoObject> | 114 | template <typename T = KAutoObject> |
| 115 | KAutoObject* GetObjectImpl(Handle handle) const { | ||
| 116 | if (!IsValid(handle)) { | ||
| 117 | return nullptr; | ||
| 118 | } | ||
| 119 | |||
| 120 | auto* obj = objects_new[static_cast<u16>(handle >> 15)]; | ||
| 121 | return obj->DynamicCast<T*>(); | ||
| 122 | } | ||
| 123 | |||
| 124 | template <typename T = KAutoObject> | ||
| 114 | KScopedAutoObject<T> GetObject(Handle handle) const { | 125 | KScopedAutoObject<T> GetObject(Handle handle) const { |
| 115 | if (handle == CurrentThread) { | 126 | if (handle == CurrentThread) { |
| 116 | return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>(); | 127 | return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>(); |
| @@ -148,6 +159,48 @@ public: | |||
| 148 | 159 | ||
| 149 | ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); | 160 | ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); |
| 150 | 161 | ||
| 162 | template <typename T> | ||
| 163 | bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { | ||
| 164 | // Try to convert and open all the handles. | ||
| 165 | size_t num_opened; | ||
| 166 | { | ||
| 167 | // Lock the table. | ||
| 168 | KScopedSpinLock lk(lock); | ||
| 169 | for (num_opened = 0; num_opened < num_handles; num_opened++) { | ||
| 170 | // Get the current handle. | ||
| 171 | const auto cur_handle = handles[num_opened]; | ||
| 172 | |||
| 173 | // Get the object for the current handle. | ||
| 174 | KAutoObject* cur_object = this->GetObjectImpl(cur_handle); | ||
| 175 | if (cur_object == nullptr) { | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Cast the current object to the desired type. | ||
| 180 | T* cur_t = cur_object->DynamicCast<T*>(); | ||
| 181 | if (cur_t == nullptr) { | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | |||
| 185 | // Open a reference to the current object. | ||
| 186 | cur_t->Open(); | ||
| 187 | out[num_opened] = cur_t; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | // If we converted every object, succeed. | ||
| 192 | if (num_opened == num_handles) { | ||
| 193 | return true; | ||
| 194 | } | ||
| 195 | |||
| 196 | // If we didn't convert entry object, close the ones we opened. | ||
| 197 | for (size_t i = 0; i < num_opened; i++) { | ||
| 198 | out[i]->Close(); | ||
| 199 | } | ||
| 200 | |||
| 201 | return false; | ||
| 202 | } | ||
| 203 | |||
| 151 | private: | 204 | private: |
| 152 | /// Stores the Object referenced by the handle or null if the slot is empty. | 205 | /// Stores the Object referenced by the handle or null if the slot is empty. |
| 153 | std::array<std::shared_ptr<Object>, MAX_COUNT> objects; | 206 | std::array<std::shared_ptr<Object>, MAX_COUNT> objects; |
| @@ -175,6 +228,8 @@ private: | |||
| 175 | /// Head of the free slots linked list. | 228 | /// Head of the free slots linked list. |
| 176 | u16 next_free_slot = 0; | 229 | u16 next_free_slot = 0; |
| 177 | 230 | ||
| 231 | mutable KSpinLock lock; | ||
| 232 | |||
| 178 | /// Underlying kernel instance that this handle table operates under. | 233 | /// Underlying kernel instance that this handle table operates under. |
| 179 | KernelCore& kernel; | 234 | KernelCore& kernel; |
| 180 | }; | 235 | }; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 790839a4b..9e8184758 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -430,65 +430,41 @@ static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, | |||
| 430 | 430 | ||
| 431 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 431 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 432 | static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, | 432 | static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, |
| 433 | u64 handle_count, s64 nano_seconds) { | 433 | u64 num_handles, s64 nano_seconds) { |
| 434 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 434 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", |
| 435 | handles_address, handle_count, nano_seconds); | 435 | handles_address, num_handles, nano_seconds); |
| 436 | 436 | ||
| 437 | auto& memory = system.Memory(); | 437 | // Ensure number of handles is valid. |
| 438 | if (!memory.IsValidVirtualAddress(handles_address)) { | 438 | R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); |
| 439 | LOG_ERROR(Kernel_SVC, | ||
| 440 | "Handle address is not a valid virtual address, handle_address=0x{:016X}", | ||
| 441 | handles_address); | ||
| 442 | return ResultInvalidPointer; | ||
| 443 | } | ||
| 444 | |||
| 445 | static constexpr u64 MaxHandles = 0x40; | ||
| 446 | |||
| 447 | if (handle_count > MaxHandles) { | ||
| 448 | LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", | ||
| 449 | MaxHandles, handle_count); | ||
| 450 | return ResultOutOfRange; | ||
| 451 | } | ||
| 452 | 439 | ||
| 453 | auto& kernel = system.Kernel(); | 440 | auto& kernel = system.Kernel(); |
| 454 | std::vector<KSynchronizationObject*> objects(handle_count); | 441 | std::vector<KSynchronizationObject*> objs(num_handles); |
| 455 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 442 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 443 | Handle* handles = system.Memory().GetPointer<Handle>(handles_address); | ||
| 456 | 444 | ||
| 457 | for (u64 i = 0; i < handle_count; ++i) { | 445 | // Copy user handles. |
| 458 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); | 446 | if (num_handles > 0) { |
| 447 | // Convert the handles to objects. | ||
| 448 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, | ||
| 449 | num_handles), | ||
| 450 | ResultInvalidHandle); | ||
| 451 | } | ||
| 459 | 452 | ||
| 460 | bool succeeded{}; | 453 | // Ensure handles are closed when we're done. |
| 461 | { | 454 | SCOPE_EXIT({ |
| 462 | auto object = handle_table.Get<KSynchronizationObject>(handle); | 455 | for (u64 i = 0; i < num_handles; ++i) { |
| 463 | if (object) { | 456 | objs[i]->Close(); |
| 464 | objects[i] = object; | ||
| 465 | succeeded = true; | ||
| 466 | } | ||
| 467 | } | 457 | } |
| 458 | }); | ||
| 468 | 459 | ||
| 469 | // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES | 460 | return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), |
| 470 | if (!succeeded) { | 461 | nano_seconds); |
| 471 | { | ||
| 472 | auto object = handle_table.GetObject<KSynchronizationObject>(handle); | ||
| 473 | |||
| 474 | if (object.IsNull()) { | ||
| 475 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); | ||
| 476 | return ResultInvalidHandle; | ||
| 477 | } | ||
| 478 | |||
| 479 | objects[i] = object.GetPointerUnsafe(); | ||
| 480 | succeeded = true; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | } | ||
| 484 | return KSynchronizationObject::Wait(kernel, index, objects.data(), | ||
| 485 | static_cast<s32>(objects.size()), nano_seconds); | ||
| 486 | } | 462 | } |
| 487 | 463 | ||
| 488 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, | 464 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, |
| 489 | s32 handle_count, u32 timeout_high, s32* index) { | 465 | s32 num_handles, u32 timeout_high, s32* index) { |
| 490 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; | 466 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; |
| 491 | return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); | 467 | return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); |
| 492 | } | 468 | } |
| 493 | 469 | ||
| 494 | /// Resumes a thread waiting on WaitSynchronization | 470 | /// Resumes a thread waiting on WaitSynchronization |