From 4ea76def7c42daac84e2eb66534babae2f141a16 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 6 Mar 2019 15:09:50 +0300 Subject: [PATCH] Update sys_lwmutex_lock and sys_lwmutex_unlock (liblv2 HLE) Implement missing SYS_SYNC_RETRY logic Following #5680 --- rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp | 67 +++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index d2b32445f0..e689e7968a 100644 --- a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -85,7 +85,7 @@ error_code sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr lwmutex) } // deleting succeeded - lwmutex->vars.owner.exchange(lwmutex_dead); + lwmutex->vars.owner.release(lwmutex_dead); return CELL_OK; } @@ -184,8 +184,57 @@ error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr lwmutex, u64 if (res == CELL_EBUSY && lwmutex->attribute & SYS_SYNC_RETRY) { - // TODO (protocol is ignored in current implementation) - fmt::throw_exception("Unimplemented" HERE); + while (true) + { + for (u32 i = 0; i < 10; i++) + { + busy_wait(); + + if (lwmutex->vars.owner.load() == lwmutex_free) + { + if (lwmutex->vars.owner.compare_and_swap_test(lwmutex_free, tid)) + { + return CELL_OK; + } + } + } + + lwmutex->all_info++; + + if (lwmutex->vars.owner.compare_and_swap_test(lwmutex_free, tid)) + { + lwmutex->all_info--; + return CELL_OK; + } + + const u64 time0 = timeout ? get_system_time() : 0; + + const error_code res_ = _sys_lwmutex_lock(ppu, lwmutex->sleep_queue, timeout); + + if (res_ == CELL_OK) + { + lwmutex->vars.owner.release(tid); + } + else if (timeout && res_ != CELL_ETIMEDOUT) + { + const u64 time_diff = get_system_time() - time0; + + if (timeout <= time_diff) + { + lwmutex->all_info--; + return not_an_error(CELL_ETIMEDOUT); + } + + timeout -= time_diff; + } + + lwmutex->all_info--; + + if (res_ != CELL_EBUSY) + { + return res_; + } + } } return res; @@ -297,11 +346,19 @@ error_code sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr lwmutex) if (lwmutex->attribute & SYS_SYNC_RETRY) { - // TODO (protocol is ignored in current implementation) + lwmutex->vars.owner.release(lwmutex_free); + + // Call the alternative syscall + if (_sys_lwmutex_unlock2(lwmutex->sleep_queue) == CELL_ESRCH) + { + return CELL_ESRCH; + } + + return CELL_OK; } // set special value - lwmutex->vars.owner.exchange(lwmutex_reserved); + lwmutex->vars.owner.release(lwmutex_reserved); // call the syscall if (_sys_lwmutex_unlock(ppu, lwmutex->sleep_queue) == CELL_ESRCH)