summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/handle_table.h55
-rw-r--r--src/core/hle/kernel/svc.cpp70
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 @@
#include "common/common_types.h"
#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
@@ -111,6 +112,16 @@ public:
}
template <typename T = KAutoObject>
+ KAutoObject* GetObjectImpl(Handle handle) const {
+ if (!IsValid(handle)) {
+ return nullptr;
+ }
+
+ auto* obj = objects_new[static_cast<u16>(handle >> 15)];
+ return obj->DynamicCast<T*>();
+ }
+
+ template <typename T = KAutoObject>
KScopedAutoObject<T> GetObject(Handle handle) const {
if (handle == CurrentThread) {
return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>();
@@ -148,6 +159,48 @@ public:
ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type);
+ template <typename T>
+ bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
+ // Try to convert and open all the handles.
+ size_t num_opened;
+ {
+ // Lock the table.
+ KScopedSpinLock lk(lock);
+ for (num_opened = 0; num_opened < num_handles; num_opened++) {
+ // Get the current handle.
+ const auto cur_handle = handles[num_opened];
+
+ // Get the object for the current handle.
+ KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
+ if (cur_object == nullptr) {
+ break;
+ }
+
+ // Cast the current object to the desired type.
+ T* cur_t = cur_object->DynamicCast<T*>();
+ if (cur_t == nullptr) {
+ break;
+ }
+
+ // Open a reference to the current object.
+ cur_t->Open();
+ out[num_opened] = cur_t;
+ }
+ }
+
+ // If we converted every object, succeed.
+ if (num_opened == num_handles) {
+ return true;
+ }
+
+ // If we didn't convert entry object, close the ones we opened.
+ for (size_t i = 0; i < num_opened; i++) {
+ out[i]->Close();
+ }
+
+ return false;
+ }
+
private:
/// Stores the Object referenced by the handle or null if the slot is empty.
std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
@@ -175,6 +228,8 @@ private:
/// Head of the free slots linked list.
u16 next_free_slot = 0;
+ mutable KSpinLock lock;
+
/// Underlying kernel instance that this handle table operates under.
KernelCore& kernel;
};
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,
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
- u64 handle_count, s64 nano_seconds) {
- LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
- handles_address, handle_count, nano_seconds);
+ u64 num_handles, s64 nano_seconds) {
+ LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
+ handles_address, num_handles, nano_seconds);
- auto& memory = system.Memory();
- if (!memory.IsValidVirtualAddress(handles_address)) {
- LOG_ERROR(Kernel_SVC,
- "Handle address is not a valid virtual address, handle_address=0x{:016X}",
- handles_address);
- return ResultInvalidPointer;
- }
-
- static constexpr u64 MaxHandles = 0x40;
-
- if (handle_count > MaxHandles) {
- LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
- MaxHandles, handle_count);
- return ResultOutOfRange;
- }
+ // Ensure number of handles is valid.
+ R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
auto& kernel = system.Kernel();
- std::vector<KSynchronizationObject*> objects(handle_count);
+ std::vector<KSynchronizationObject*> objs(num_handles);
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+ Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
- for (u64 i = 0; i < handle_count; ++i) {
- const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
+ // Copy user handles.
+ if (num_handles > 0) {
+ // Convert the handles to objects.
+ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
+ num_handles),
+ ResultInvalidHandle);
+ }
- bool succeeded{};
- {
- auto object = handle_table.Get<KSynchronizationObject>(handle);
- if (object) {
- objects[i] = object;
- succeeded = true;
- }
+ // Ensure handles are closed when we're done.
+ SCOPE_EXIT({
+ for (u64 i = 0; i < num_handles; ++i) {
+ objs[i]->Close();
}
+ });
- // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES
- if (!succeeded) {
- {
- auto object = handle_table.GetObject<KSynchronizationObject>(handle);
-
- if (object.IsNull()) {
- LOG_ERROR(Kernel_SVC, "Object is a nullptr");
- return ResultInvalidHandle;
- }
-
- objects[i] = object.GetPointerUnsafe();
- succeeded = true;
- }
- }
- }
- return KSynchronizationObject::Wait(kernel, index, objects.data(),
- static_cast<s32>(objects.size()), nano_seconds);
+ return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
+ nano_seconds);
}
static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
- s32 handle_count, u32 timeout_high, s32* index) {
+ s32 num_handles, u32 timeout_high, s32* index) {
const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
- return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds);
+ return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
}
/// Resumes a thread waiting on WaitSynchronization