Преглед изворни кода

Thread: Fix WaitSynchronization1 to not set register 1 on thread wakeup.

bunnei пре 11 година
родитељ
комит
68ddaaa2f5
3 измењених фајлова са 45 додато и 25 уклоњено
  1. 28 15
      src/core/hle/kernel/thread.cpp
  2. 14 7
      src/core/hle/kernel/thread.h
  3. 3 3
      src/core/hle/svc.cpp

+ 28 - 15
src/core/hle/kernel/thread.cpp

@@ -205,25 +205,24 @@ static Thread* NextThread() {
 
 
 void WaitCurrentThread_Sleep() {
 void WaitCurrentThread_Sleep() {
     Thread* thread = GetCurrentThread();
     Thread* thread = GetCurrentThread();
-    thread->wait_all = false;
-    thread->wait_address = 0;
-    thread->wait_objects.clear();
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
 }
 }
 
 
-void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all) {
+void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all) {
     Thread* thread = GetCurrentThread();
     Thread* thread = GetCurrentThread();
+    thread->wait_set_output = wait_set_output;
     thread->wait_all = wait_all;
     thread->wait_all = wait_all;
-    thread->wait_address = 0;
-    thread->wait_objects.push_back(wait_object);
+
+    // It's possible to call WaitSynchronizationN without any objects passed in...
+    if (wait_object != nullptr)
+        thread->wait_objects.push_back(wait_object);
+
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
 }
 }
 
 
 void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
 void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
     Thread* thread = GetCurrentThread();
     Thread* thread = GetCurrentThread();
-    thread->wait_all = false;
     thread->wait_address = wait_address;
     thread->wait_address = wait_address;
-    thread->wait_objects.clear();
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
     ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
 }
 }
 
 
@@ -239,8 +238,11 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
         return;
         return;
     }
     }
 
 
-    thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, 
-        ErrorSummary::StatusChanged, ErrorLevel::Info), -1);
+    thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
+        ErrorSummary::StatusChanged, ErrorLevel::Info));
+
+    if (thread->wait_set_output)
+        thread->SetWaitSynchronizationOutput(-1);
 
 
     thread->ResumeFromWait();
     thread->ResumeFromWait();
 }
 }
@@ -282,12 +284,18 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) {
     if (wait_all) {
     if (wait_all) {
         // Resume the thread only if all are available...
         // Resume the thread only if all are available...
         if (!wait_all_failed) {
         if (!wait_all_failed) {
-            SetReturnValue(RESULT_SUCCESS, -1);
+            SetWaitSynchronizationResult(RESULT_SUCCESS);
+            SetWaitSynchronizationOutput(-1);
+
             ResumeFromWait();
             ResumeFromWait();
         }
         }
     } else {
     } else {
         // Otherwise, resume
         // Otherwise, resume
-        SetReturnValue(RESULT_SUCCESS, index);
+        SetWaitSynchronizationResult(RESULT_SUCCESS);
+
+        if (wait_set_output)
+            SetWaitSynchronizationOutput(index);
+
         ResumeFromWait();
         ResumeFromWait();
     }
     }
 }
 }
@@ -303,6 +311,7 @@ void Thread::ResumeFromWait() {
         wait_object->RemoveWaitingThread(this);
         wait_object->RemoveWaitingThread(this);
 
 
     wait_objects.clear();
     wait_objects.clear();
+    wait_set_output = false;
     wait_all = false;
     wait_all = false;
     wait_address = 0;
     wait_address = 0;
 
 
@@ -371,6 +380,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
     thread->stack_size = stack_size;
     thread->stack_size = stack_size;
     thread->initial_priority = thread->current_priority = priority;
     thread->initial_priority = thread->current_priority = priority;
     thread->processor_id = processor_id;
     thread->processor_id = processor_id;
+    thread->wait_set_output = false;
     thread->wait_all = false;
     thread->wait_all = false;
     thread->wait_objects.clear();
     thread->wait_objects.clear();
     thread->wait_address = 0;
     thread->wait_address = 0;
@@ -462,9 +472,12 @@ void Reschedule() {
     }
     }
 }
 }
 
 
-void Thread::SetReturnValue(ResultCode return_val, s32 out_val) {
-    context.cpu_registers[0] = return_val.raw;
-    context.cpu_registers[1] = out_val;
+void Thread::SetWaitSynchronizationResult(ResultCode result) {
+    context.cpu_registers[0] = result.raw;
+}
+
+void Thread::SetWaitSynchronizationOutput(s32 output) {
+    context.cpu_registers[1] = output;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////////

+ 14 - 7
src/core/hle/kernel/thread.h

@@ -78,11 +78,16 @@ public:
     void ResumeFromWait();
     void ResumeFromWait();
 
 
     /**
     /**
-     * Sets the output values after the thread awakens from WaitSynchronization
-     * @param return_val Value returned
-     * @param out_val Value to set to the output parameter
+     * Sets the result after the thread awakens (from either WaitSynchronization SVC)
+     * @param result Value to set to the returned result
      */
      */
-    void SetReturnValue(ResultCode return_val, s32 out_val);
+    void SetWaitSynchronizationResult(ResultCode result);
+
+    /**
+     * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only)
+     * @param output Value to set to the output parameter
+     */
+    void SetWaitSynchronizationOutput(s32 output);
 
 
     Core::ThreadContext context;
     Core::ThreadContext context;
 
 
@@ -100,8 +105,9 @@ public:
 
 
     std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
     std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
 
 
-    VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address 
-    bool wait_all;      ///< True if the thread is waiting on all objects before resuming
+    VAddr wait_address;     ///< If waiting on an AddressArbiter, this is the arbitration address
+    bool wait_all;          ///< True if the thread is waiting on all objects before resuming
+    bool wait_set_output;   ///< True if the output parameter should be set on thread wakeup
 
 
     std::string name;
     std::string name;
 
 
@@ -134,9 +140,10 @@ void WaitCurrentThread_Sleep();
 /**
 /**
  * Waits the current thread from a WaitSynchronization call
  * Waits the current thread from a WaitSynchronization call
  * @param wait_object Kernel object that we are waiting on
  * @param wait_object Kernel object that we are waiting on
+ * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only)
  * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
  * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
  */
  */
-void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all = false);
+void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all);
 
 
 /**
 /**
  * Waits the current thread from an ArbitrateAddress call
  * Waits the current thread from an ArbitrateAddress call

+ 3 - 3
src/core/hle/svc.cpp

@@ -126,7 +126,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
     if (object->ShouldWait()) {
     if (object->ShouldWait()) {
 
 
         object->AddWaitingThread(Kernel::GetCurrentThread());
         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
         // Create an event to wake the thread up after the specified nanosecond delay has passed
         Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
         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
         // NOTE: This should deadlock the current thread if no timeout was specified
         if (!wait_all) {
         if (!wait_all) {
             wait_thread = true;
             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) {
         for (int i = 0; i < handle_count; ++i) {
             auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
             auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
             object->AddWaitingThread(Kernel::GetCurrentThread());
             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
         // Create an event to wake the thread up after the specified nanosecond delay has passed