summaryrefslogtreecommitdiffstats
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r--src/core/hle/svc.cpp77
1 files changed, 50 insertions, 27 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a487f757c..170ac87f3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -133,6 +133,9 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
if (wait.Succeeded() && *wait) {
// Create an event to wake the thread up after the specified nanosecond delay has passed
Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
+
+ Kernel::GetCurrentThread()->SetWaitAll(false);
+
HLE::Reschedule(__func__);
}
@@ -140,44 +143,64 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
- s64 nano_seconds) {
-
- // TODO(bunnei): Do something with nano_seconds, currently ignoring this
- bool unlock_all = true;
- bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
+static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
+ bool wait_thread = false;
+ bool wait_all_succeeded = false;
+ int handle_index = 0;
- LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
- handle_count, (wait_all ? "true" : "false"), nano_seconds);
-
- // Iterate through each handle, synchronize kernel object
- for (s32 i = 0; i < handle_count; i++) {
- SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]);
+ while (handle_index < handle_count) {
+ SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[handle_index]);
if (object == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw;
- LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i],
- object->GetTypeName().c_str(), object->GetName().c_str());
+ ResultVal<bool> wait = object->WaitSynchronization(handle_index);
- // TODO(yuriks): Verify how the real function behaves when an error happens here
- ResultVal<bool> wait_result = object->WaitSynchronization();
- bool wait = wait_result.Succeeded() && *wait_result;
+ wait_thread = (wait.Succeeded() && *wait);
- if (!wait && !wait_all) {
- *out = i;
- return RESULT_SUCCESS.raw;
- } else {
- unlock_all = false;
+ // If this object waited and we are waiting on all objects to synchronize
+ if (wait_thread && wait_all) {
+ // Enforce later on that this thread does not continue
+ wait_all_succeeded = true;
}
+
+ // If this object synchronized and we are not waiting on all objects to synchronize
+ if (!wait_thread && !wait_all)
+ // We're done, the thread will continue
+ break;
+
+ handle_index++;
+ }
+
+ // Change the thread state to waiting if blocking on all handles...
+ if (wait_thread || wait_all_succeeded) {
+ // Create an event to wake the thread up after the specified nanosecond delay has passed
+ Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
+ Kernel::GetCurrentThread()->SetWaitAll(wait_all);
+
+ HLE::Reschedule(__func__);
+
+ // NOTE: output of this SVC will be set later depending on how the thread resumes
+ return RESULT_DUMMY.raw;
}
- if (wait_all && unlock_all) {
- *out = handle_count;
- return RESULT_SUCCESS.raw;
+ // Acquire objects if we did not wait...
+ for (int i = 0; i < handle_count; ++i) {
+ auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
+
+ // Acquire the object if it is not waiting...
+ if (!object->ShouldWait()) {
+ object->Acquire();
+
+ // If this was the first non-waiting object and 'wait_all' is false, don't acquire
+ // any other objects
+ if (!wait_all)
+ break;
+ }
}
- // Check for next thread to schedule
- HLE::Reschedule(__func__);
+ // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
+ // not seem to set it to any meaningful value.
+ *out = wait_all ? 0 : handle_index;
return RESULT_SUCCESS.raw;
}