From 66bd8308d9f0d70116298b880db4f2cbe04d922a Mon Sep 17 00:00:00 2001 From: Eladash Date: Sat, 28 Mar 2020 06:16:59 +0300 Subject: [PATCH] lv2: Wait for rescheduling before confirming timeouts (#7875) --- rpcs3/Emu/Cell/lv2/sys_event.cpp | 9 +++++++-- rpcs3/Emu/Cell/lv2/sys_event_flag.cpp | 9 +++++++-- rpcs3/Emu/Cell/lv2/sys_lwcond.cpp | 29 +++++++++++++++++++-------- rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp | 9 +++++++-- rpcs3/Emu/Cell/lv2/sys_mutex.cpp | 9 +++++++-- rpcs3/Emu/Cell/lv2/sys_net.cpp | 18 +++++++++++++---- rpcs3/Emu/Cell/lv2/sys_rwlock.cpp | 18 +++++++++++++---- rpcs3/Emu/Cell/lv2/sys_semaphore.cpp | 9 +++++++-- 8 files changed, 84 insertions(+), 26 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index 0849c3eaa2..f7037a219d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -291,12 +291,17 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptrmutex); if (!queue->unqueue(queue->sq, &ppu)) { - timeout = 0; - continue; + break; } ppu.gpr[3] = CELL_ETIMEDOUT; diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index aacd06ec1e..c6c21ba0db 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -170,12 +170,17 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(flag->mutex); if (!flag->unqueue(flag->sq, &ppu)) { - timeout = 0; - continue; + break; } flag->waiters--; diff --git a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp index 2ed65bc0e3..27c552c52e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp @@ -356,18 +356,31 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id { if (lv2_obj::wait_timeout(timeout, &ppu)) { - std::lock_guard lock(cond->mutex); - - if (!cond->unqueue(cond->sq, &ppu)) + // Wait for rescheduling + if (ppu.check_state()) { - timeout = 0; - continue; + return 0; } - cond->waiters--; + std::lock_guard lock(cond->mutex); - ppu.gpr[3] = CELL_ETIMEDOUT; - break; + if (cond->unqueue(cond->sq, &ppu)) + { + cond->waiters--; + ppu.gpr[3] = CELL_ETIMEDOUT; + break; + } + + std::lock_guard lock2(mutex->mutex); + + if (std::find(mutex->sq.cbegin(), mutex->sq.cend(), &ppu) == mutex->sq.cend()) + { + break; + } + + mutex->sleep(ppu); + timeout = 0; + continue; } } else diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 876eef5f4b..8245582aac 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -164,12 +164,17 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout) { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(mutex->mutex); if (!mutex->unqueue(mutex->sq, &ppu)) { - timeout = 0; - continue; + break; } ppu.gpr[3] = CELL_ETIMEDOUT; diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index 564ec73b59..2b239542f0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -164,12 +164,17 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout) { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(mutex->mutex); if (!mutex->unqueue(mutex->sq, &ppu)) { - timeout = 0; - continue; + break; } ppu.gpr[3] = CELL_ETIMEDOUT; diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp index 12b662ebd5..51635567b2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -1889,12 +1889,17 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr fds, s32 n { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard nw_lock(g_fxo->get()->s_nw_mutex); if (signaled) { - timeout = 0; - continue; + break; } network_clear_queue(ppu); @@ -2080,12 +2085,17 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptrget()->s_nw_mutex); if (signaled) { - timeout = 0; - continue; + break; } network_clear_queue(ppu); diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index 10ebc00ac9..17b945dc1a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -139,12 +139,17 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout) { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(rwlock->mutex); if (!rwlock->unqueue(rwlock->rq, &ppu)) { - timeout = 0; - continue; + break; } ppu.gpr[3] = CELL_ETIMEDOUT; @@ -336,12 +341,17 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout) { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(rwlock->mutex); if (!rwlock->unqueue(rwlock->wq, &ppu)) { - timeout = 0; - continue; + break; } // If the last waiter quit the writer sleep queue, wake blocked readers diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 72ee32aa4d..f637258130 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -130,12 +130,17 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout) { if (lv2_obj::wait_timeout(timeout, &ppu)) { + // Wait for rescheduling + if (ppu.check_state()) + { + return 0; + } + std::lock_guard lock(sem->mutex); if (!sem->unqueue(sem->sq, &ppu)) { - timeout = 0; - continue; + break; } verify(HERE), 0 > sem->val.fetch_op([](s32& val)