From cfe154d9160efa41896aae1477baf1f89ea2cc4d Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 5 Feb 2014 15:55:32 +0400 Subject: [PATCH] Small changes, some bugs fixed --- Utilities/BEType.h | 4 + Utilities/SMutex.cpp | 26 ++++ Utilities/SMutex.h | 151 ++++++++++++++++++++ rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl | 2 +- rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp | 50 +------ rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h | 72 +++++----- rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp | 6 +- rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp | 1 + rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp | 12 +- rpcs3/rpcs3.vcxproj | 2 + rpcs3/rpcs3.vcxproj.filters | 6 + 13 files changed, 242 insertions(+), 94 deletions(-) create mode 100644 Utilities/SMutex.cpp create mode 100644 Utilities/SMutex.h diff --git a/Utilities/BEType.h b/Utilities/BEType.h index cc6a6fed62..cfd2c4265e 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -2,6 +2,10 @@ #include "Utilities/GNU.h" +#define se16(x) const_se_t::value +#define se32(x) const_se_t::value +#define se64(x) const_se_t::value + template struct se_t; template struct se_t { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } }; template struct se_t { static __forceinline void func(T& dst, const T src) { (u16&)dst = _byteswap_ushort((u16&)src); } }; diff --git a/Utilities/SMutex.cpp b/Utilities/SMutex.cpp new file mode 100644 index 0000000000..3c1eecb3fc --- /dev/null +++ b/Utilities/SMutex.cpp @@ -0,0 +1,26 @@ +#include +#include + +__forceinline void SM_Sleep() +{ + Sleep(1); +} + +__forceinline DWORD SM_GetCurrentThreadId() +{ + return GetCurrentThreadId(); +} + +__forceinline u32 SM_GetCurrentCPUThreadId() +{ + if (CPUThread* t = GetCurrentCPUThread()) + { + return t->GetId(); + } + return 0; +} + +__forceinline be_t SM_GetCurrentCPUThreadIdBE() +{ + return SM_GetCurrentCPUThreadId(); +} \ No newline at end of file diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h new file mode 100644 index 0000000000..e24cbd1326 --- /dev/null +++ b/Utilities/SMutex.h @@ -0,0 +1,151 @@ +#pragma once +#include + +extern void SM_Sleep(); +extern DWORD SM_GetCurrentThreadId(); +extern u32 SM_GetCurrentCPUThreadId(); +extern be_t SM_GetCurrentCPUThreadIdBE(); + +enum SMutexResult +{ + SMR_OK = 0, // succeeded (lock, trylock, unlock) + SMR_FAILED, // failed (trylock, unlock) + SMR_DEADLOCK, // mutex reached deadlock (lock, trylock) + SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread + SMR_PERMITTED, // not owner of the mutex (unlock) + SMR_ABORT, // emulator has been stopped (lock, trylock, unlock) + SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock) + SMR_TIMEOUT, // timed out (lock) +}; + +template +< + typename T, + u32 free_value = 0, + u32 dead_value = ~0, + void (wait)() = SM_Sleep +> +class SMutexBase +{ + static_assert(sizeof(T) == 4, "Invalid SMutexBase typename"); + std::atomic owner; + +public: + SMutexBase() + : owner((T)free_value) + { + } + + ~SMutexBase() + { + lock((T)dead_value); + owner = (T)dead_value; + } + + __forceinline T GetOwner() const + { + return (T&)owner; + } + + SMutexResult trylock(T tid) + { + T old = (T)free_value; + + if (!owner.compare_exchange_strong(old, tid)) + { + if (old == tid) + { + return SMR_DEADLOCK; + } + if (Emu.IsStopped()) + { + return SMR_ABORT; + } + if (old == (T)dead_value) + { + return SMR_DESTROYED; + } + + return SMR_FAILED; + } + + return SMR_OK; + } + + SMutexResult unlock(T tid, T to = (T)free_value) + { + T old = tid; + + if (!owner.compare_exchange_strong(old, to)) + { + if (old == (T)free_value) + { + return SMR_FAILED; + } + if (old == (T)dead_value) + { + return SMR_DESTROYED; + } + + return SMR_PERMITTED; + } + + return SMR_OK; + } + + SMutexResult lock(T tid, u64 timeout = 0) + { + u64 counter = 0; + + while (true) + { + switch (SMutexResult res = trylock(tid)) + { + case SMR_FAILED: break; + default: return res; + } + + wait(); + + if (timeout && counter++ > timeout) + { + return SMR_TIMEOUT; + } + } + } +}; + +template +class SMutexLockerBase +{ + typedef SMutexBase T_SMutex; + T_SMutex& sm; + const T tid; + + SMutexLockerBase(T_SMutex& _sm) + : sm(_sm) + , tid(get_tid()) + { + if (!tid) throw "SMutexLockerBase: invalid thread id"; + sm.lock(tid); + } + + ~SMutexLockerBase() + { + sm.unlock(tid); + } +}; + +typedef SMutexBase + SMutexGeneral; +typedef SMutexBase + SMutex; +typedef SMutexBase> + SMutexBE; + +typedef SMutexLockerBase + SMutexGeneralLocker; +typedef SMutexLockerBase + SMutexLocker; +typedef SMutexLockerBase, SM_GetCurrentCPUThreadIdBE> + SMutexBELocker; \ No newline at end of file diff --git a/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl b/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl index b59dbca43c..7af30bc435 100644 --- a/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl +++ b/rpcs3/Emu/Memory/DynamicMemoryBlockBase.inl @@ -78,7 +78,7 @@ void DynamicMemoryBlockBase::Delete() template bool DynamicMemoryBlockBase::AllocFixed(u64 addr, u32 size) { - size = PAGE_4K(size); // align size + size = PAGE_4K(size + (addr & 4095)); // align size addr &= ~4095; // align start address diff --git a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp index 707651a5e8..cd29d5e144 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_GCM.cpp @@ -7,7 +7,7 @@ extern gcmInfo gcm_info; int cellGcmCallback(u32 context_addr, u32 count) { - GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); + GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); // could stall on exit CellGcmContextData& ctx = (CellGcmContextData&)Memory[context_addr]; CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp index 5ff20ac90d..9ab3eb73c1 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp @@ -95,7 +95,7 @@ int sys_lwcond_wait(mem_ptr_t lwcond, u64 timeout) const u32 tid = GetCurrentPPUThread().GetId(); mem_ptr_t lwmutex((u32)lwcond->lwmutex_addr); - if ((u32)lwmutex->owner != tid) return CELL_EPERM; // caller must own this lwmutex + if ((u32)lwmutex->owner.GetOwner() != tid) return CELL_EPERM; // caller must own this lwmutex lwc->begin_waiting(tid); u32 counter = 0; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index 418774e5e4..d9636db949 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/lv2/SC_Lwmutex.h" +#include "Utilities/SMutex.h" #include SysCallBase sc_lwmutex("sys_lwmutex"); -std::mutex g_lwmutex; - int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_t attr) { sc_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)", @@ -49,20 +48,9 @@ int sys_lwmutex_destroy(mem_ptr_t lwmutex) if (!lwmutex->attribute) return CELL_EINVAL; - { // global lock - std::lock_guard lock(g_lwmutex); - - if (!lwmutex->owner) - { - lwmutex->owner = ~0; // make it unable to lock - lwmutex->attribute = 0; - } - else - { - return CELL_EBUSY; - } - } - + // try to make it unable to lock + if (lwmutex->owner.trylock(~0) != SMR_OK) return CELL_EBUSY; + lwmutex->attribute = 0; return CELL_OK; } @@ -74,35 +62,7 @@ int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) if (!lwmutex->attribute) return CELL_EINVAL; - const u32 tid = GetCurrentPPUThread().GetId(); - - int res = lwmutex->trylock(tid); - if (res != CELL_EBUSY) return res; - - u32 counter = 0; - const u32 max_counter = timeout ? (timeout / 1000) : 20000; - do // waiting - { - if (Emu.IsStopped()) return CELL_ETIMEDOUT; - Sleep(1); - - res = lwmutex->trylock(tid); - if (res != CELL_EBUSY) return res; - if (!lwmutex->attribute) return CELL_EINVAL; - - if (counter++ > max_counter) - { - if (!timeout) - { - sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr()); - counter = 0; - } - else - { - return CELL_ETIMEDOUT; - } - } - } while (true); + return lwmutex->lock(GetCurrentPPUThread().GetId(), timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0); } int sys_lwmutex_trylock(mem_ptr_t lwmutex) diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h index 1072d7eca5..5996282c5c 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h @@ -1,4 +1,5 @@ #pragma once +#include // attr_protocol (waiting scheduling policy) enum @@ -33,16 +34,14 @@ struct sys_lwmutex_attribute_t char name[8]; }; -extern std::mutex g_lwmutex; - struct sys_lwmutex_t { union // sys_lwmutex_variable_t { struct // sys_lwmutex_lock_info_t { - /* volatile */ be_t owner; - /* volatile */ be_t waiter; + /* volatile */ SMutexBE owner; + /* volatile */ be_t waiter; // not used }; struct { @@ -56,75 +55,74 @@ struct sys_lwmutex_t int trylock(u32 tid) { - std::lock_guard lock(g_lwmutex); // global lock - - if ((u32)attribute & SYS_SYNC_RECURSIVE) + if (tid == (u32)owner.GetOwner()) // recursive or deadlock { - if (tid == (u32)owner) + if (attribute & se32(SYS_SYNC_RECURSIVE)) { - recursive_count = (u32)recursive_count + 1; - if ((u32)recursive_count == 0xffffffff) return CELL_EKRESOURCE; + recursive_count += 1; + if (!recursive_count) return CELL_EKRESOURCE; return CELL_OK; } - } - else // recursive not allowed - { - if (tid == (u32)owner) + else { return CELL_EDEADLK; } } - - if (!(u32)owner) // try lock + switch (owner.trylock(tid)) { - owner = tid; - recursive_count = 1; - return CELL_OK; - } - else - { - return CELL_EBUSY; + case SMR_OK: recursive_count = 1; return CELL_OK; + default: return CELL_EBUSY; } } bool unlock(u32 tid) { - std::lock_guard lock(g_lwmutex); // global lock - - if (tid != (u32)owner) + if (tid != (u32)owner.GetOwner()) { return false; } else { - recursive_count = (u32)recursive_count - 1; - if (!(u32)recursive_count) + recursive_count -= 1; + if (!recursive_count) { - waiter = 0; // not used yet - owner = 0; // release + owner.unlock(tid); } return true; } } + + int lock(u32 tid, u64 timeout) + { + switch (int res = trylock(tid)) + { + case CELL_OK: return CELL_OK; + case CELL_EBUSY: break; + default: return res; + } + switch (owner.lock(tid, timeout)) + { + case SMR_OK: recursive_count = 1; return CELL_OK; + case SMR_TIMEOUT: return CELL_ETIMEDOUT; + default: return CELL_EINVAL; + } + } }; -struct lwmutex_locker +class lwmutex_locker { -private: mem_ptr_t m_mutex; u32 m_id; -public: - const int res; - lwmutex_locker(u32 lwmutex_addr, u32 tid) + lwmutex_locker(u32 lwmutex_addr, u32 tid, u64 timeout = 0) : m_id(tid) , m_mutex(lwmutex_addr) - , res(m_mutex->trylock(m_id)) { + if (int res = m_mutex->lock(m_id, timeout)) throw "lwmutex_locker: m_mutex->lock failed"; } ~lwmutex_locker() { - if (res == CELL_OK) m_mutex->unlock(m_id); + m_mutex->unlock(m_id); } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp index 8705ca09c6..526e1d56ab 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp @@ -45,18 +45,18 @@ int sys_memory_container_destroy(u32 cid) int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr) { //0x30000100; - sc_mem.Warning("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags); + sc_mem.Log("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags); u32 addr; switch(flags) { case SYS_MEMORY_PAGE_SIZE_1M: if(size & 0xfffff) return CELL_EALIGN; - addr = Memory.Alloc(size, 0x100000); + addr = Memory.Alloc(size, 1); break; case SYS_MEMORY_PAGE_SIZE_64K: if(size & 0xffff) return CELL_EALIGN; - addr = Memory.Alloc(size, 0x10000); + addr = Memory.Alloc(size, 1); break; default: return CELL_EINVAL; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp index 75681aba06..2bd289413a 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "SC_Mutex.h" +#include "Utilities/SMutex.h" SysCallBase sys_mtx("sys_mutex"); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp index c3499e14d1..b5286becae 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp @@ -10,16 +10,16 @@ int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t attr if (!rw_lock_id.IsGood() || !attr.IsGood()) return CELL_EFAULT; - switch ((u32)attr->attr_protocol) + switch (attr->attr_protocol) { - case SYS_SYNC_PRIORITY: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; - case SYS_SYNC_RETRY: sys_rwlock.Error("Invalid SYS_SYNC_RETRY attr"); break; - case SYS_SYNC_PRIORITY_INHERIT: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case SYS_SYNC_FIFO: break; + case se32(SYS_SYNC_PRIORITY): sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; + case se32(SYS_SYNC_RETRY): sys_rwlock.Error("Invalid SYS_SYNC_RETRY attr"); break; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; + case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } - if ((u32)attr->attr_pshared != 0x200) + if (attr->attr_pshared != se32(0x200)) { sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared); return CELL_EINVAL; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index e3ee7a4c26..a1508186ac 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -205,6 +205,7 @@ NotUsing NotUsing + @@ -324,6 +325,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index abbb2365a1..81d08d002f 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -379,6 +379,9 @@ Emu\FS + + Utilities + @@ -558,5 +561,8 @@ Include + + Utilities + \ No newline at end of file