From 67a144df2a7b7f3018aefd49c123b1f8601e763a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 30 Jan 2014 00:31:09 +0400 Subject: [PATCH] SC_Rwlock implementation, SC_Lwcond draft Other small changes --- rpcs3/Emu/SysCalls/Modules/cellPamf.cpp | 16 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 7 + rpcs3/Emu/SysCalls/SysCalls.h | 9 ++ rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp | 81 ++++++++++ rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h | 24 +++ rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp | 43 ++++-- rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp | 141 +++++++++++++++-- rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h | 154 ++++++++++++++++++- rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp | 6 +- rpcs3/rpcs3.vcxproj | 1 + rpcs3/rpcs3.vcxproj.filters | 3 + 11 files changed, 451 insertions(+), 34 deletions(-) create mode 100644 rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp create mode 100644 rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index 1e33d4d572..ee7f8d2973 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -365,6 +365,8 @@ int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, mem_ptr_t pSelf) { + cellPamf.Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.GetAddr()); + return pSelf->stream; } @@ -506,7 +508,7 @@ int cellPamfReaderGetNumberOfEp(mem_ptr_t pSelf) int cellPamfReaderGetEpIteratorWithIndex(mem_ptr_t pSelf, u32 epIndex, mem_ptr_t pIt) { - cellPamf.Warning("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x (stream=%d), epIndex=%d, pIt_addr=0x%x)", + cellPamf.Error("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x (stream=%d), epIndex=%d, pIt_addr=0x%x)", pSelf.GetAddr(), pSelf->stream, epIndex, pIt.GetAddr()); const mem_ptr_t pAddr(pSelf->pAddr); @@ -516,19 +518,25 @@ int cellPamfReaderGetEpIteratorWithIndex(mem_ptr_t pSelf, u32 ep int cellPamfReaderGetEpIteratorWithTimeStamp(mem_ptr_t pSelf, mem_ptr_t pTimeStamp, mem_ptr_t pIt) { - UNIMPLEMENTED_FUNC(cellPamf); + cellPamf.Error("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", + pSelf.GetAddr(), pTimeStamp.GetAddr(), pIt.GetAddr()); + + const mem_ptr_t pAddr(pSelf->pAddr); + //TODO: return CELL_OK; } int cellPamfEpIteratorGetEp(mem_ptr_t pIt, mem_ptr_t pEp) { - UNIMPLEMENTED_FUNC(cellPamf); + cellPamf.Error("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.GetAddr(), pEp.GetAddr()); + //TODO: return CELL_OK; } int cellPamfEpIteratorMove(mem_ptr_t pIt, int steps, mem_ptr_t pEp) { - UNIMPLEMENTED_FUNC(cellPamf); + cellPamf.Error("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.GetAddr(), steps, pEp.GetAddr()); + //TODO: return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index e08e90cae4..dd43be259e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -175,4 +175,11 @@ void sysPrxForUser_init() sysPrxForUser.AddFunc(0x893305fa, sys_raw_spu_load); sysPrxForUser.AddFunc(0xb995662e, sys_raw_spu_image_load); + + sysPrxForUser.AddFunc(0xda0eb71a, sys_lwcond_create); + sysPrxForUser.AddFunc(0x1c9a942c, sys_lwcond_destroy); + sysPrxForUser.AddFunc(0xef87a695, sys_lwcond_signal); + sysPrxForUser.AddFunc(0xe9a1bd84, sys_lwcond_signal_all); + sysPrxForUser.AddFunc(0x52aadadf, sys_lwcond_signal_to); + sysPrxForUser.AddFunc(0x2a6d9d51, sys_lwcond_wait); } diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 6158e81a1f..7c18cb6df0 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -6,6 +6,7 @@ #include "lv2/SC_Rwlock.h" #include "lv2/SC_SPU_Thread.h" #include "lv2/SC_Lwmutex.h" +#include "lv2/SC_Lwcond.h" #include "Emu/event.h" //#define SYSCALLS_DEBUG @@ -147,6 +148,14 @@ extern int sys_semaphore_trywait(u32 sem); extern int sys_semaphore_post(u32 sem, int count); extern int sys_semaphore_get_value(u32 sem, u32 count_addr); +//sys_lwcond +extern int sys_lwcond_create(mem_ptr_t lwcond, mem_ptr_t lwmutex, mem_ptr_t attr); +extern int sys_lwcond_destroy(mem_ptr_t lwcond); +extern int sys_lwcond_signal(mem_ptr_t lwcond); +extern int sys_lwcond_signal_all(mem_ptr_t lwcond); +extern int sys_lwcond_signal_to(mem_ptr_t lwcond, u32 ppu_thread_id); +extern int sys_lwcond_wait(mem_ptr_t lwcond, u64 timeout); + //sys_lwmutex extern int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_t attr); extern int sys_lwmutex_destroy(mem_ptr_t lwmutex); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp new file mode 100644 index 0000000000..da208a6495 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp @@ -0,0 +1,81 @@ +#include "stdafx.h" +#include "Emu/SysCalls/SysCalls.h" +#include "SC_Lwmutex.h" +#include "SC_Lwcond.h" + +SysCallBase sys_lwcond("sys_lwcond"); + +int sys_lwcond_create(mem_ptr_t lwcond, mem_ptr_t lwmutex, mem_ptr_t attr) +{ + sys_lwcond.Warning("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", + lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr()); + + if (!lwcond.IsGood() || !lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT; + + lwcond->lwmutex_addr = lwmutex.GetAddr(); + lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(*(u64*)&attr->name)); + + sys_lwcond.Warning("*** lwcond created [%s]", attr->name); + return CELL_OK; +} + +int sys_lwcond_destroy(mem_ptr_t lwcond) +{ + sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr()); + + if (!lwcond.IsGood()) return CELL_EFAULT; + LWCond* lwc; + u32 id = (u32)lwcond->lwcond_queue; + if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; + + Emu.GetIdManager().RemoveID(id); + return CELL_OK; +} + +int sys_lwcond_signal(mem_ptr_t lwcond) +{ + sys_lwcond.Warning("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); + + if (!lwcond.IsGood()) return CELL_EFAULT; + LWCond* lwc; + u32 id = (u32)lwcond->lwcond_queue; + if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; + + return CELL_OK; +} + +int sys_lwcond_signal_all(mem_ptr_t lwcond) +{ + sys_lwcond.Warning("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr()); + + if (!lwcond.IsGood()) return CELL_EFAULT; + LWCond* lwc; + u32 id = (u32)lwcond->lwcond_queue; + if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; + + return CELL_OK; +} + +int sys_lwcond_signal_to(mem_ptr_t lwcond, u32 ppu_thread_id) +{ + sys_lwcond.Warning("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id); + + if (!lwcond.IsGood()) return CELL_EFAULT; + LWCond* lwc; + u32 id = (u32)lwcond->lwcond_queue; + if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; + + return CELL_OK; +} + +int sys_lwcond_wait(mem_ptr_t lwcond, u64 timeout) +{ + sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%llu)", lwcond.GetAddr(), timeout); + + if (!lwcond.IsGood()) return CELL_EFAULT; + LWCond* lwc; + u32 id = (u32)lwcond->lwcond_queue; + if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; + + return CELL_OK; +} diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h new file mode 100644 index 0000000000..30eab02f61 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h @@ -0,0 +1,24 @@ +#pragma once + +struct sys_lwcond_attribute_t +{ + char name[8]; +}; + +struct sys_lwcond_t +{ + be_t lwmutex_addr; + be_t lwcond_queue; +}; + +#pragma pack() + +struct LWCond +{ + u64 m_name; + + LWCond(u64 name) + : m_name(name) + { + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index c1e2779df4..ad313f9334 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -23,10 +23,10 @@ int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_tattr_protocol) { - case SYS_SYNC_PRIORITY: break; - case SYS_SYNC_RETRY: sc_lwmutex.Error("TODO: SYS_SYNC_RETRY attr"); break; - case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Error("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case SYS_SYNC_FIFO: sc_lwmutex.Error("TODO: SYS_SYNC_FIFO attr"); break; + case SYS_SYNC_PRIORITY: sc_lwmutex.Log("TODO: SYS_SYNC_PRIORITY attr"); break; + case SYS_SYNC_RETRY: sc_lwmutex.Warning("TODO: SYS_SYNC_RETRY attr"); break; + case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; + case SYS_SYNC_FIFO: sc_lwmutex.Log("TODO: SYS_SYNC_FIFO attr"); break; default: return CELL_EINVAL; } @@ -36,15 +36,31 @@ int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_trecursive_count = 0; lwmutex->sleep_queue = 0; - sc_lwmutex.Log("*** lwmutex created [%s] (protocol=0x%x, recursive=0x%x)", - attr->name, (u32)attr->attr_protocol, (u32)attr->attr_recursive); + sc_lwmutex.Log("*** lwmutex created [%s] (attribute=0x%x)", attr->name, (u32)lwmutex->attribute); return CELL_OK; } int sys_lwmutex_destroy(mem_ptr_t lwmutex) { - sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); + sc_lwmutex.Log("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); + + if (!lwmutex.IsGood()) return CELL_EFAULT; + + if (!lwmutex->attribute) return CELL_EINVAL; + + { // global lock + std::lock_guard lock(g_lwmutex); + + if (!lwmutex->owner) + { + lwmutex->attribute = 0; + } + else + { + return CELL_EBUSY; + } + } return CELL_OK; } @@ -55,6 +71,8 @@ int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) if (!lwmutex.IsGood()) return CELL_EFAULT; + if (!lwmutex->attribute) return CELL_EINVAL; + PPCThread& thr = GetCurrentPPUThread(); const u32 id = thr.GetId(); @@ -80,7 +98,7 @@ int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) if (!lwmutex->owner) // lock { - lwmutex->owner = id; + lwmutex->owner = id; lwmutex->recursive_count = 1; return CELL_OK; } @@ -91,6 +109,7 @@ int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) const u32 max_counter = timeout ? (timeout / 1000) : 20000; do // waiting { + if (Emu.IsStopped()) return CELL_ETIMEDOUT; Sleep(1); { // global lock @@ -108,9 +127,9 @@ int sys_lwmutex_lock(mem_ptr_t lwmutex, u64 timeout) if (counter++ > max_counter) { if (!timeout) - { // endless waiter - sc_lwmutex.Error("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr()); - return CELL_OK; + { + sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr()); + counter = 0; } else { @@ -126,6 +145,8 @@ int sys_lwmutex_trylock(mem_ptr_t lwmutex) if (!lwmutex.IsGood()) return CELL_EFAULT; + if (!lwmutex->attribute) return CELL_EINVAL; + PPCThread& thr = GetCurrentPPUThread(); const u32 id = thr.GetId(); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp index c17c90cf58..1cadd83e07 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.cpp @@ -6,48 +6,169 @@ SysCallBase sys_rwlock("sys_rwlock"); int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t attr) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.GetAddr(), attr.GetAddr()); + sys_rwlock.Warning("sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.GetAddr(), attr.GetAddr()); + + if (!rw_lock_id.IsGood() || !attr.IsGood()) return CELL_EFAULT; + + switch ((u32)attr->attr_protocol) + { + case SYS_SYNC_PRIORITY: sys_rwlock.Log("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; + default: return CELL_EINVAL; + } + + if ((u32)attr->attr_pshared != 0x200) + { + sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared); + return CELL_EINVAL; + } + + rw_lock_id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, (u32)attr->attr_pshared, + (u64)attr->key, (s32)attr->flags, *(u64*)&attr->name)); + + sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x)", attr->name, (u32)attr->attr_protocol); + return CELL_OK; } int sys_rwlock_destroy(u32 rw_lock_id) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_destroy(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Warning("sys_rwlock_destroy(rw_lock_id=%d)", rw_lock_id); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + + std::lock_guard lock(rw->m_lock); + + if (rw->wlock_queue.GetCount() || rw->rlock_list.GetCount() || rw->wlock_thread) return CELL_EBUSY; + + Emu.GetIdManager().RemoveID(rw_lock_id); + return CELL_OK; } int sys_rwlock_rlock(u32 rw_lock_id, u64 timeout) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); - return CELL_OK; + sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + PPCThread& thr = GetCurrentPPUThread(); + const u32 id = thr.GetId(); + + if (rw->rlock_trylock(id)) return CELL_OK; + + u32 counter = 0; + const u32 max_counter = timeout ? (timeout / 1000) : 20000; + do + { + if (Emu.IsStopped()) return CELL_ETIMEDOUT; + Sleep(1); + + if (rw->rlock_trylock(id)) return CELL_OK; + + if (counter++ > max_counter) + { + if (!timeout) + { + sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d): TIMEOUT", rw_lock_id); + counter = 0; + } + else + { + return CELL_ETIMEDOUT; + } + } + } while (true); } int sys_rwlock_tryrlock(u32 rw_lock_id) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Warning("sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + + if (!rw->rlock_trylock(GetCurrentPPUThread().GetId())) return CELL_EBUSY; + return CELL_OK; } int sys_rwlock_runlock(u32 rw_lock_id) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Warning("sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + + if (!rw->rlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM; + return CELL_OK; } int sys_rwlock_wlock(u32 rw_lock_id, u64 timeout) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); - return CELL_OK; + sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + PPCThread& thr = GetCurrentPPUThread(); + const u32 id = thr.GetId(); + + if (!rw->wlock_check(id)) return CELL_EDEADLK; + + if (rw->wlock_trylock(id, true)) return CELL_OK; + + u32 counter = 0; + const u32 max_counter = timeout ? (timeout / 1000) : 20000; + do + { + if (Emu.IsStopped()) return CELL_ETIMEDOUT; + Sleep(1); + + if (rw->wlock_trylock(id, true)) return CELL_OK; + + if (counter++ > max_counter) + { + if (!timeout) + { + sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d): TIMEOUT", rw_lock_id); + counter = 0; + } + else + { + return CELL_ETIMEDOUT; + } + } + } while (true); } int sys_rwlock_trywlock(u32 rw_lock_id) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Warning("sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + PPCThread& thr = GetCurrentPPUThread(); + const u32 id = thr.GetId(); + + if (!rw->wlock_check(id)) return CELL_EDEADLK; + + if (!rw->wlock_trylock(id, false)) return CELL_EBUSY; + return CELL_OK; } int sys_rwlock_wunlock(u32 rw_lock_id) { - sys_rwlock.Warning("Unimplemented function: sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id); + sys_rwlock.Warning("sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id); + + RWLock* rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + + if (!rw->wlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM; + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h index d986b59a98..c63782ef09 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Rwlock.h @@ -2,11 +2,153 @@ struct sys_rwlock_attribute_t { - u32 attr_protocol; //sys_protocol_t - u32 attr_pshared; //sys_process_shared_t - u64 key; //sys_ipc_key_t - s32 flags; - u8 name[8]; + be_t attr_protocol; + be_t attr_pshared; // == 0x200 (NOT SHARED) + be_t key; // process-shared key (not used) + be_t flags; // process-shared flags (not used) + be_t pad; + char name[8]; }; -#pragma pack() \ No newline at end of file +#pragma pack() + +struct RWLock +{ + std::mutex m_lock; // internal lock + u32 wlock_thread; // write lock owner + Array wlock_queue; // write lock queue + Array rlock_list; // read lock list + u32 m_protocol; // TODO + + u32 m_pshared; // not used + u64 m_key; // not used + s32 m_flags; // not used + union + { + u64 m_name_data; // not used + char m_name[8]; + }; + + RWLock(u32 protocol, u32 pshared, u64 key, s32 flags, u64 name) + : m_protocol(protocol) + , m_pshared(pshared) + , m_key(key) + , m_flags(flags) + , m_name_data(name) + , wlock_thread(0) + { + } + + bool rlock_trylock(u32 id) + { + std::lock_guard lock(m_lock); + + if (!wlock_thread && !wlock_queue.GetCount()) + { + rlock_list.AddCpy(id); + return true; + } + return false; + } + + bool rlock_unlock(u32 id) + { + std::lock_guard lock(m_lock); + + for (u32 i = rlock_list.GetCount() - 1; ~i; i--) + { + if (rlock_list[i] == id) + { + rlock_list.RemoveAt(i); + return true; + } + } + return false; + } + + bool wlock_check(u32 id) + { + std::lock_guard lock(m_lock); + + if (wlock_thread == id) + { + return false; // deadlock + } + for (u32 i = rlock_list.GetCount() - 1; ~i; i--) + { + if (rlock_list[i] == id) + { + return false; // deadlock + } + } + return true; + } + + bool wlock_trylock(u32 id, bool enqueue) + { + std::lock_guard lock(m_lock); + + if (wlock_thread || rlock_list.GetCount()) // already locked + { + if (!enqueue) + { + return false; // do not enqueue + } + for (u32 i = wlock_queue.GetCount() - 1; ~i; i--) + { + if (wlock_queue[i] == id) + { + return false; // already enqueued + } + } + wlock_queue.AddCpy(id); // enqueue new thread + return false; + } + else + { + if (wlock_queue.GetCount()) + { + // SYNC_FIFO only yet + if (wlock_queue[0] == id) + { + wlock_thread = id; + wlock_queue.RemoveAt(0); + return true; + } + else + { + if (!enqueue) + { + return false; // do not enqueue + } + for (u32 i = wlock_queue.GetCount() - 1; ~i; i--) + { + if (wlock_queue[i] == id) + { + return false; // already enqueued + } + } + wlock_queue.AddCpy(id); // enqueue new thread + return false; + } + } + else + { + wlock_thread = id; // easy way + return true; + } + } + } + + bool wlock_unlock(u32 id) + { + std::lock_guard lock(m_lock); + + if (wlock_thread == id) + { + wlock_thread = 0; + return true; + } + return false; + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index f79ce5cf7b..341e36fcaa 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -15,7 +15,7 @@ struct SpuGroupInfo { CPUThread* threads[g_spu_group_thr_count]; sys_spu_thread_group_attribute& attr; - volatile long lock; + std::atomic lock; SpuGroupInfo(sys_spu_thread_group_attribute& attr) : attr(attr), lock(0) { @@ -259,7 +259,7 @@ int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) return CELL_ESRCH; } - if (_InterlockedCompareExchange(&group_info->lock, 1, 0)) //get lock + if (group_info->lock.exchange(1)) //get lock { return CELL_EBUSY; } @@ -275,7 +275,7 @@ int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) } } - _InterlockedExchange(&group_info->lock, 0); //release lock + group_info->lock = 0; //release lock return CELL_OK; } diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 5f76f44462..e8e50cafc2 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -249,6 +249,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 65591d896f..45dd7d3051 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -370,6 +370,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\lv2 +