From fb448461df10ebbf09f35b3b0e299bcdf2ca858e Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 7 Aug 2014 11:59:56 +0400 Subject: [PATCH] cellSyncBarrierNotify --- rpcs3/Emu/SysCalls/Modules/cellSync.cpp | 61 +++++++++++++++++++++++-- rpcs3/Emu/SysCalls/Modules/cellSync.h | 4 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index ded18c4d2d..901e51c0e2 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -159,7 +159,7 @@ s32 cellSyncBarrierInitialize(mem_ptr_t barrier, u16 total_coun s32 cellSyncBarrierNotify(mem_ptr_t barrier) { - cellSync->Todo("cellSyncBarrierNotify(barrier_addr=0x%x)", barrier.GetAddr()); + cellSync->Log("cellSyncBarrierNotify(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { @@ -170,13 +170,42 @@ s32 cellSyncBarrierNotify(mem_ptr_t barrier) return CELL_SYNC_ERROR_ALIGN; } - // TODO + // prx: sync, extract m_value, repeat if < 0, increase, compare with second s16, set sign bit if equal, insert it back + InterlockedCompareExchange(&barrier->m_data(), 0, 0); + + while (true) + { + const u32 old_data = barrier->m_data(); + CellSyncBarrier new_barrier; + new_barrier.m_data() = old_data; + + s16 value = (s16)new_barrier.m_value; + if (value < 0) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + if (Emu.IsStopped()) + { + LOG_WARNING(HLE, "cellSyncBarrierNotify(barrier_addr=0x%x) aborted", barrier.GetAddr()); + return CELL_OK; + } + continue; + } + + value++; + if (value == (s16)new_barrier.m_count) + { + value |= 0x8000; + } + new_barrier.m_value = value; + if (InterlockedCompareExchange(&barrier->m_data(), new_barrier.m_data(), old_data) == old_data) break; + } + return CELL_OK; } s32 cellSyncBarrierTryNotify(mem_ptr_t barrier) { - cellSync->Todo("cellSyncBarrierTryNotify(barrier_addr=0x%x)", barrier.GetAddr()); + cellSync->Log("cellSyncBarrierTryNotify(barrier_addr=0x%x)", barrier.GetAddr()); if (!barrier) { @@ -187,7 +216,31 @@ s32 cellSyncBarrierTryNotify(mem_ptr_t barrier) return CELL_SYNC_ERROR_ALIGN; } - // TODO + InterlockedCompareExchange(&barrier->m_data(), 0, 0); + + while (true) + { + const u32 old_data = barrier->m_data(); + CellSyncBarrier new_barrier; + new_barrier.m_data() = old_data; + + s16 value = (s16)new_barrier.m_value; + if (value >= 0) + { + value++; + if (value == (s16)new_barrier.m_count) + { + value |= 0x8000; + } + new_barrier.m_value = value; + if (InterlockedCompareExchange(&barrier->m_data(), new_barrier.m_data(), old_data) == old_data) break; + } + else + { + if (InterlockedCompareExchange(&barrier->m_data(), new_barrier.m_data(), old_data) == old_data) return CELL_SYNC_ERROR_BUSY; + } + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.h b/rpcs3/Emu/SysCalls/Modules/cellSync.h index a1ef8fdf39..00c753e3be 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.h @@ -44,8 +44,8 @@ static_assert(sizeof(CellSyncMutex) == 4, "CellSyncMutex: wrong size"); struct CellSyncBarrier { - be_t m_value; - be_t m_count; + be_t m_value; + be_t m_count; volatile u32& m_data() {