From 7faf2d8e06e705d1866fa0d7848ff43541a4b172 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 02:03:44 -0500 Subject: WaitSynchronizationN: Implement return values --- src/core/hle/svc.cpp | 77 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 27 deletions(-) (limited to 'src/core/hle/svc.cpp') 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 object = Kernel::g_handle_table.GetGeneric(handles[i]); + while (handle_index < handle_count) { + SharedPtr 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 wait = object->WaitSynchronization(handle_index); - // TODO(yuriks): Verify how the real function behaves when an error happens here - ResultVal 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; } -- cgit v1.2.3 From 064be2b86f166d40e0ba61bc4ec0306631b4be9f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 12:17:36 -0500 Subject: WaitSynchronizationN: Handle case where handle_count=0. --- src/core/hle/svc.cpp | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 170ac87f3..f8a5b2548 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -148,27 +148,37 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all_succeeded = false; int handle_index = 0; - while (handle_index < handle_count) { - SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); - if (object == nullptr) - return InvalidHandle(ErrorModule::Kernel).raw; - - ResultVal wait = object->WaitSynchronization(handle_index); - - wait_thread = (wait.Succeeded() && *wait); + // If handles were passed in, iterate through them and wait/acquire the objects as needed + if (handle_count > 0) { + while (handle_index < handle_count) { + SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); + if (object == nullptr) + return InvalidHandle(ErrorModule::Kernel).raw; + + ResultVal wait = object->WaitSynchronization(handle_index); + + wait_thread = (wait.Succeeded() && *wait); + + // 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; - // 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; + handle_index++; + } + }else { + // If no handles were passed in, put the thread to sleep only when wait_all=false + // NOTE: This is supposed to deadlock if no timeout was specified + if (!wait_all) { + wait_thread = true; + Kernel::WaitCurrentThread(WAITTYPE_SLEEP); } - - // 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... -- cgit v1.2.3 From f5c6d367c9634291aeea7604c2a14a80144f7dc0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 12:35:55 -0500 Subject: WaitSynchronizationN: Handle case where handle_count is invalid. --- src/core/hle/svc.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index f8a5b2548..637c63b91 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -148,8 +148,12 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all_succeeded = false; int handle_index = 0; - // If handles were passed in, iterate through them and wait/acquire the objects as needed - if (handle_count > 0) { + // Negative handle_count is invalid + if (handle_count < 0) + return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; + + // If handle_count is non-zero, iterate through them and wait/acquire the objects as needed + if (handle_count != 0) { while (handle_index < handle_count) { SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); if (object == nullptr) @@ -172,7 +176,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, handle_index++; } - }else { + } else { // If no handles were passed in, put the thread to sleep only when wait_all=false // NOTE: This is supposed to deadlock if no timeout was specified if (!wait_all) { -- cgit v1.2.3 From 627e96fc15f99eea0f1c5ccdb46d85cadb3efd69 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 14:04:54 -0500 Subject: WaitSynchronizationN: Handle case where handles=nullptr. --- src/core/hle/svc.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 637c63b91..23885f129 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -148,6 +148,10 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all_succeeded = false; int handle_index = 0; + // Handles pointer is invalid + if (handles == nullptr) + return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; + // Negative handle_count is invalid if (handle_count < 0) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; -- cgit v1.2.3 From aa01c57ae9d73e41b65d37860ca6fbb91caba33a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 22:23:49 -0500 Subject: Kernel: Separate WaitSynchronization into Wait and Acquire methods. --- src/core/hle/svc.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 23885f129..a27aa6269 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -127,7 +127,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - ResultVal wait = object->WaitSynchronization(); + ResultVal wait = object->Wait(); // Check for next thread to schedule if (wait.Succeeded() && *wait) { @@ -137,6 +137,8 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Kernel::GetCurrentThread()->SetWaitAll(false); HLE::Reschedule(__func__); + } else { + object->Acquire(); } return wait.Code().raw; @@ -163,15 +165,14 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - ResultVal wait = object->WaitSynchronization(handle_index); + ResultVal wait = object->Wait(handle_index); wait_thread = (wait.Succeeded() && *wait); // If this object waited and we are waiting on all objects to synchronize - if (wait_thread && wait_all) { + 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) -- cgit v1.2.3 From 6643673f28b9273149fc945849a13ed832e9ef33 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 01:27:46 -0500 Subject: WaitSynchronizationN: Refactor to fix several bugs - Separate wait checking from waiting the current thread - Resume thread when wait_all=true only if all objects are available at once - Set output to correct wait object index when there are duplicate handles --- src/core/hle/svc.cpp | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a27aa6269..059451100 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -127,7 +127,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - ResultVal wait = object->Wait(); + ResultVal wait = object->Wait(true); // Check for next thread to schedule if (wait.Succeeded() && *wait) { @@ -146,8 +146,7 @@ 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) { - bool wait_thread = false; - bool wait_all_succeeded = false; + bool wait_thread = !wait_all; int handle_index = 0; // Handles pointer is invalid @@ -158,40 +157,43 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (handle_count < 0) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; - // If handle_count is non-zero, iterate through them and wait/acquire the objects as needed + // If handle_count is non-zero, iterate through them and wait the current thread on the objects if (handle_count != 0) { - while (handle_index < handle_count) { - SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); + bool selected = false; // True once an object has been selected + for (int i = 0; i < handle_count; ++i) { + SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[i]); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - ResultVal wait = object->Wait(handle_index); - - wait_thread = (wait.Succeeded() && *wait); - - // 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++; + ResultVal wait = object->Wait(true); + + // Check if the current thread should wait on the object... + if (wait.Succeeded() && *wait) { + // Check we are waiting on all objects... + if (wait_all) + // Wait the thread + wait_thread = true; + } else { + // Do not wait on this object, check if this object should be selected... + if (!wait_all && !selected) { + // Do not wait the thread + wait_thread = false; + handle_index = i; + selected = true; + } + } } } else { // If no handles were passed in, put the thread to sleep only when wait_all=false - // NOTE: This is supposed to deadlock if no timeout was specified + // NOTE: This is supposed to deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; Kernel::WaitCurrentThread(WAITTYPE_SLEEP); } } - // Change the thread state to waiting if blocking on all handles... - if (wait_thread || wait_all_succeeded) { + // If thread should block, then set its state to waiting and then reschedule... + if (wait_thread) { // 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); @@ -199,7 +201,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, HLE::Reschedule(__func__); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_DUMMY.raw; + return 0xDEADBEEF; } // Acquire objects if we did not wait... -- cgit v1.2.3 From 6deb1a0119eb4f17490ed2603d5a608bcf71413a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 02:16:54 -0500 Subject: WaitSynchronizationN: Improved comments --- src/core/hle/svc.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 059451100..01b536084 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -149,15 +149,20 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_thread = !wait_all; int handle_index = 0; - // Handles pointer is invalid + // Check if 'handles' is invalid if (handles == nullptr) return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; - // Negative handle_count is invalid + // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If + // this happens, the running application will crash. + _assert_msg_(Kernel, out != nullptr, "invalid output pointer specified!"); + + // Check if 'handle_count' is invalid if (handle_count < 0) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; - // If handle_count is non-zero, iterate through them and wait the current thread on the objects + // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if + // necessary if (handle_count != 0) { bool selected = false; // True once an object has been selected for (int i = 0; i < handle_count; ++i) { @@ -167,7 +172,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, ResultVal wait = object->Wait(true); - // Check if the current thread should wait on the object... + // Check if the current thread should wait on this object... if (wait.Succeeded() && *wait) { // Check we are waiting on all objects... if (wait_all) @@ -184,15 +189,15 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, } } } else { - // If no handles were passed in, put the thread to sleep only when wait_all=false - // NOTE: This is supposed to deadlock the current thread if no timeout was specified + // If no handles were passed in, put the thread to sleep only when 'wait_all' is false + // NOTE: This should deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; Kernel::WaitCurrentThread(WAITTYPE_SLEEP); } } - // If thread should block, then set its state to waiting and then reschedule... + // If thread should wait, then set its state to waiting and then reschedule... if (wait_thread) { // Create an event to wake the thread up after the specified nanosecond delay has passed Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); -- cgit v1.2.3 From e5a9f1c64483e01b7856c581ae5685d0c5ad88dc Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:25:51 -0500 Subject: Kernel: Get rid of WaitTypes and simplify lots of code, removing hacks. --- src/core/hle/svc.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 01b536084..2d5f41af6 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -105,7 +105,7 @@ static Result SendSyncRequest(Handle handle) { ResultVal wait = session->SyncRequest(); if (wait.Succeeded() && *wait) { - Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? + Kernel::WaitCurrentThread(); // TODO(bunnei): Is this correct? } return wait.Code().raw; @@ -120,22 +120,24 @@ static Result CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { - SharedPtr object = Kernel::g_handle_table.GetGeneric(handle); + Kernel::WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handle).get()); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - ResultVal wait = object->Wait(true); + ResultVal wait = object->Wait(); // Check for next thread to schedule if (wait.Succeeded() && *wait) { + + object->AddWaitingThread(Kernel::GetCurrentThread()); + Kernel::WaitCurrentThread_WaitSynchronization(object); + // 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__); } else { object->Acquire(); @@ -166,14 +168,15 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (handle_count != 0) { bool selected = false; // True once an object has been selected for (int i = 0; i < handle_count; ++i) { - SharedPtr object = Kernel::g_handle_table.GetGeneric(handles[i]); + Kernel::WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handles[i]).get()); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - ResultVal wait = object->Wait(true); + ResultVal wait = object->Wait(); // Check if the current thread should wait on this object... if (wait.Succeeded() && *wait) { + // Check we are waiting on all objects... if (wait_all) // Wait the thread @@ -193,15 +196,22 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, // NOTE: This should deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; - Kernel::WaitCurrentThread(WAITTYPE_SLEEP); + Kernel::WaitCurrentThread(); } } // If thread should wait, then set its state to waiting and then reschedule... if (wait_thread) { + + // Actually wait the current thread on each object if we decided to wait... + for (int i = 0; i < handle_count; ++i) { + auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); + object->AddWaitingThread(Kernel::GetCurrentThread()); + Kernel::WaitCurrentThread_WaitSynchronization(object, wait_all); + } + // 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__); @@ -440,7 +450,7 @@ static void SleepThread(s64 nanoseconds) { LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); // Sleep current thread and check for next thread to schedule - Kernel::WaitCurrentThread(WAITTYPE_SLEEP); + Kernel::WaitCurrentThread(); // Create an event to wake the thread up after the specified nanosecond delay has passed Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); -- cgit v1.2.3 From 254e4ebd58a31e8462b70799f95f096d0d0038f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:56:40 -0500 Subject: AddressArbiter: Changed to Kernel::Object, big cleanup, removed code that made no sense. --- src/core/hle/svc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 2d5f41af6..cf029bf69 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -105,7 +105,7 @@ static Result SendSyncRequest(Handle handle) { ResultVal wait = session->SyncRequest(); if (wait.Succeeded() && *wait) { - Kernel::WaitCurrentThread(); // TODO(bunnei): Is this correct? + Kernel::WaitCurrentThread_Sleep(); // TODO(bunnei): Is this correct? } return wait.Code().raw; @@ -196,7 +196,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, // NOTE: This should deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; - Kernel::WaitCurrentThread(); + Kernel::WaitCurrentThread_Sleep(); } } @@ -450,7 +450,7 @@ static void SleepThread(s64 nanoseconds) { LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); // Sleep current thread and check for next thread to schedule - Kernel::WaitCurrentThread(); + Kernel::WaitCurrentThread_Sleep(); // Create an event to wake the thread up after the specified nanosecond delay has passed Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); -- cgit v1.2.3 From c06d64528a666f450e42cb1792ac995fc1697e76 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 14:00:10 -0500 Subject: SVC: Removed a Sleep that made no sense - Would deadlock the calling thread - Code would never get hit anyways --- src/core/hle/svc.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index cf029bf69..5e9c38973 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -103,12 +103,7 @@ static Result SendSyncRequest(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); - ResultVal wait = session->SyncRequest(); - if (wait.Succeeded() && *wait) { - Kernel::WaitCurrentThread_Sleep(); // TODO(bunnei): Is this correct? - } - - return wait.Code().raw; + return session->SyncRequest().Code().raw; } /// Close a handle -- cgit v1.2.3 From 9412996c8f86f5da5a9052f7533b05e9780c4eb0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 14:33:11 -0500 Subject: Kernel: Moved Wait and Acquire to WaitObject, added way to retrieve a WaitObject safely. --- src/core/hle/svc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 5e9c38973..8df861669 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -115,7 +115,7 @@ static Result CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { - Kernel::WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handle).get()); + auto object = Kernel::g_handle_table.GetWaitObject(handle); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; @@ -163,7 +163,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (handle_count != 0) { bool selected = false; // True once an object has been selected for (int i = 0; i < handle_count; ++i) { - Kernel::WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handles[i]).get()); + auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; -- cgit v1.2.3 From d2759c578e8cf24277767f701d5682f7b1792a9f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 18:01:58 -0500 Subject: Kernel: Reschedule on SignalEvent and SendSyncRequest, fix some bugs. --- src/core/hle/svc.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 8df861669..d72839172 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -405,6 +405,7 @@ static Result DuplicateHandle(Handle* out, Handle handle) { /// Signals an event static Result SignalEvent(Handle evt) { LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); + HLE::Reschedule(__func__); return Kernel::SignalEvent(evt).raw; } -- cgit v1.2.3 From c68eb1569549ae49ae25c6c29cec2e10d8329f2d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 17:41:12 -0500 Subject: WaitObject: Renamed "Wait" to "ShouldWait", made "ShouldWait" and "Acquire" pure virtual. --- src/core/hle/svc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index d72839172..fd2d22727 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -122,7 +122,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - ResultVal wait = object->Wait(); + ResultVal wait = object->ShouldWait(); // Check for next thread to schedule if (wait.Succeeded() && *wait) { @@ -167,7 +167,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - ResultVal wait = object->Wait(); + ResultVal wait = object->ShouldWait(); // Check if the current thread should wait on this object... if (wait.Succeeded() && *wait) { -- cgit v1.2.3 From 15b6a4d9add6b260a2a1a84ab6228addced4f851 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:16:45 -0500 Subject: Kernel: Changed "ShouldWait" to return bool and "Acquire" to return void. --- src/core/hle/svc.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index fd2d22727..f6c912502 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -122,10 +122,8 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - ResultVal wait = object->ShouldWait(); - // Check for next thread to schedule - if (wait.Succeeded() && *wait) { + if (object->ShouldWait()) { object->AddWaitingThread(Kernel::GetCurrentThread()); Kernel::WaitCurrentThread_WaitSynchronization(object); @@ -138,7 +136,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { object->Acquire(); } - return wait.Code().raw; + return RESULT_SUCCESS.raw; } /// Wait for the given handles to synchronize, timeout after the specified nanoseconds @@ -167,10 +165,8 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - ResultVal wait = object->ShouldWait(); - // Check if the current thread should wait on this object... - if (wait.Succeeded() && *wait) { + if (object->ShouldWait()) { // Check we are waiting on all objects... if (wait_all) -- cgit v1.2.3 From 68ddaaa2f5726e3619accee77b488ec285f3a2d7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 20:53:52 -0500 Subject: Thread: Fix WaitSynchronization1 to not set register 1 on thread wakeup. --- src/core/hle/svc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index f6c912502..89095ac91 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -126,7 +126,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { if (object->ShouldWait()) { object->AddWaitingThread(Kernel::GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(object); + Kernel::WaitCurrentThread_WaitSynchronization(object, false, false); // Create an event to wake the thread up after the specified nanosecond delay has passed Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); @@ -187,7 +187,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, // NOTE: This should deadlock the current thread if no timeout was specified if (!wait_all) { wait_thread = true; - Kernel::WaitCurrentThread_Sleep(); + Kernel::WaitCurrentThread_WaitSynchronization(nullptr, true, wait_all); } } @@ -198,7 +198,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); object->AddWaitingThread(Kernel::GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(object, wait_all); + Kernel::WaitCurrentThread_WaitSynchronization(object, true, wait_all); } // Create an event to wake the thread up after the specified nanosecond delay has passed -- cgit v1.2.3 From 731154f79e4f2e417a9db97e125eadb26b6b6f06 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 21 Jan 2015 18:27:01 -0500 Subject: WaitSynchronization: Added a result code for invalid result, fixed bug. --- src/core/hle/svc.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/core/hle/svc.cpp') diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 89095ac91..2d922046e 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -29,6 +29,9 @@ using Kernel::SharedPtr; namespace SVC { +/// An invalid result code that is meant to be overwritten when a thread resumes from waiting +const ResultCode RESULT_INVALID(0xDEADC0DE); + enum ControlMemoryOperation { MEMORY_OPERATION_HEAP = 0x00000003, MEMORY_OPERATION_GSP_HEAP = 0x00010003, @@ -132,10 +135,13 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); HLE::Reschedule(__func__); - } else { - object->Acquire(); + + // NOTE: output of this SVC will be set later depending on how the thread resumes + return RESULT_INVALID.raw; } + object->Acquire(); + return RESULT_SUCCESS.raw; } @@ -207,7 +213,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, HLE::Reschedule(__func__); // NOTE: output of this SVC will be set later depending on how the thread resumes - return 0xDEADBEEF; + return RESULT_INVALID.raw; } // Acquire objects if we did not wait... -- cgit v1.2.3