From 314dc4c5de7bcba8407ca6cd0c34580777f3ba62 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 4 Jun 2020 13:27:25 +0300 Subject: [PATCH] sys_cond: Fix spurious EBUSY in sys_cond_destroy Increment waiters count inside IDM's mutex lock scope. --- rpcs3/Emu/Cell/lv2/sys_cond.cpp | 53 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index 7a0a82e70d..2107a70822 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -205,16 +205,35 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout); - const auto cond = idm::get(cond_id, [&](lv2_cond& cond) + // Further function result + ppu.gpr[3] = CELL_OK; + + const auto cond = idm::get(cond_id, [&](lv2_cond& cond) -> s64 { - if (cond.mutex->owner >> 1 == ppu.id) + if (cond.mutex->owner >> 1 != ppu.id) { - // Add a "promise" to add a waiter - cond.waiters++; + return -1; } + std::lock_guard lock(cond.mutex->mutex); + + // Register waiter + cond.sq.emplace_back(&ppu); + cond.waiters++; + + // Unlock the mutex + const auto count = cond.mutex->lock_count.exchange(0); + + if (auto cpu = cond.mutex->reown()) + { + cond.mutex->append(cpu); + } + + // Sleep current thread and schedule mutex waiter + cond.sleep(ppu, timeout); + // Save the recursive value - return cond.mutex->lock_count.load(); + return count; }); if (!cond) @@ -222,32 +241,10 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) return CELL_ESRCH; } - // Verify ownership - if (cond->mutex->owner >> 1 != ppu.id) + if (cond.ret < 0) { return CELL_EPERM; } - else - { - // Further function result - ppu.gpr[3] = CELL_OK; - - std::lock_guard lock(cond->mutex->mutex); - - // Register waiter - cond->sq.emplace_back(&ppu); - - // Unlock the mutex - cond->mutex->lock_count = 0; - - if (auto cpu = cond->mutex->reown()) - { - cond->mutex->append(cpu); - } - - // Sleep current thread and schedule mutex waiter - cond->sleep(ppu, timeout); - } while (!ppu.state.test_and_reset(cpu_flag::signal)) {