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> ConditionVariable::Create(VAddr guest_addr, - VAddr mutex_addr, std::string name) { SharedPtr 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> Create(VAddr guest_addr, VAddr mutex_addr = 0, + static ResultVal> 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 condition_variable = g_object_address_table.Get(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, @@ -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; }