From 0b6b147939c3abd1f98ecf639fb1ee51c5a445a1 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 4 Feb 2018 12:30:51 -0500
Subject: [PATCH] WaitProcessWideKeyAtomic: Handle case where condition
 variable was already created.

---
 src/core/hle/kernel/condition_variable.cpp |  3 +--
 src/core/hle/kernel/condition_variable.h   |  4 +---
 src/core/hle/kernel/svc.cpp                | 23 ++++++++++++++--------
 3 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/src/core/hle/kernel/condition_variable.cpp b/src/core/hle/kernel/condition_variable.cpp
index 5616663847..a786d7f740 100644
--- a/src/core/hle/kernel/condition_variable.cpp
+++ b/src/core/hle/kernel/condition_variable.cpp
@@ -15,13 +15,12 @@ ConditionVariable::ConditionVariable() {}
 ConditionVariable::~ConditionVariable() {}
 
 ResultVal<SharedPtr<ConditionVariable>> ConditionVariable::Create(VAddr guest_addr,
-                                                                  VAddr mutex_addr,
                                                                   std::string name) {
     SharedPtr<ConditionVariable> condition_variable(new ConditionVariable);
 
     condition_variable->name = std::move(name);
     condition_variable->guest_addr = guest_addr;
-    condition_variable->mutex_addr = mutex_addr;
+    condition_variable->mutex_addr = 0;
 
     // Condition variables are referenced by guest address, so track this in the kernel
     g_object_address_table.Insert(guest_addr, condition_variable);
diff --git a/src/core/hle/kernel/condition_variable.h b/src/core/hle/kernel/condition_variable.h
index 0d54031cb3..1c9f067694 100644
--- a/src/core/hle/kernel/condition_variable.h
+++ b/src/core/hle/kernel/condition_variable.h
@@ -19,12 +19,10 @@ public:
      * Creates a condition variable.
      * @param guest_addr Address of the object tracking the condition variable in guest memory. If
      * specified, this condition variable will update the guest object when its state changes.
-     * @param mutex_addr Optional address of a guest mutex associated with this condition variable,
-     * used by the OS for implementing events.
      * @param name Optional name of condition variable.
      * @return The created condition variable.
      */
-    static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr, VAddr mutex_addr = 0,
+    static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr,
                                                           std::string name = "Unknown");
 
     std::string GetTypeName() const override {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4e395ed316..0705b264d6 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -612,20 +612,29 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
         mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr);
     }
 
-    ASSERT(mutex->GetOwnerHandle() == thread_handle);
-
     SharedPtr<ConditionVariable> condition_variable =
         g_object_address_table.Get<ConditionVariable>(condition_variable_addr);
     if (!condition_variable) {
         // Create a new condition_variable for the specified address if one does not already exist
-        condition_variable =
-            ConditionVariable::Create(condition_variable_addr, mutex_addr).Unwrap();
+        condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap();
         condition_variable->name =
             Common::StringFromFormat("condition-variable-%llx", condition_variable_addr);
     }
 
-    ASSERT(condition_variable->GetAvailableCount() == 0);
-    ASSERT(condition_variable->mutex_addr == mutex_addr);
+    if (condition_variable->mutex_addr) {
+        // Previously created the ConditionVariable using WaitProcessWideKeyAtomic, verify
+        // everything is correct
+        ASSERT(condition_variable->mutex_addr == mutex_addr);
+    } else {
+        // Previously created the ConditionVariable using SignalProcessWideKey, set the mutex
+        // associated with it
+        condition_variable->mutex_addr = mutex_addr;
+    }
+
+    if (mutex->GetOwnerHandle()) {
+        // Release the mutex if the current thread is holding it
+        mutex->Release(thread.get());
+    }
 
     auto wakeup_callback = [mutex, nano_seconds](ThreadWakeupReason reason,
                                                  SharedPtr<Thread> thread,
@@ -667,8 +676,6 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
     CASCADE_CODE(
         WaitSynchronization1(condition_variable, thread.get(), nano_seconds, wakeup_callback));
 
-    mutex->Release(thread.get());
-
     return RESULT_SUCCESS;
 }
 
-- 
GitLab