diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index de19a0fab6..b5f59e1ee7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -167,10 +167,8 @@ s32 spursInit( } } - if (s32 res = lwmutex_create(spurs->m.mutex, SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, *(u64*)"_spuPrv")) - { - assert(!"lwmutex_create() failed"); - } + lwmutex_create(spurs->m.mutex, false, SYS_SYNC_PRIORITY, *(u64*)"_spuPrv"); + if (s32 res = lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv")) { assert(!"lwcond_create() failed"); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 55d0636cc0..6104cb99fb 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -11,7 +11,6 @@ #include "Emu/SysCalls/lv2/sys_interrupt.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_spinlock.h" #include "Emu/SysCalls/lv2/sys_prx.h" #include "Emu/SysCalls/lv2/sys_ppu_thread.h" #include "Emu/SysCalls/lv2/sys_process.h" @@ -33,6 +32,8 @@ u32 g_tls_size; std::array, TLS_MAX> g_tls_owners; +waiter_map_t g_sys_spinlock_wm("sys_spinlock_wm"); // TODO + void sys_initialize_tls() { sysPrxForUser.Log("sys_initialize_tls()"); @@ -89,6 +90,262 @@ void ppu_free_tls(u32 thread) } } +s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) +{ + sysPrxForUser.Warning("sys_lwmutex_create(lwmutex=*0x%x, attr=*0x%x)", lwmutex, attr); + + const bool recursive = attr->recursive.data() == se32(SYS_SYNC_RECURSIVE); + + if (!recursive && attr->recursive.data() != se32(SYS_SYNC_NOT_RECURSIVE)) + { + sysPrxForUser.Error("sys_lwmutex_create(): invalid recursive attribute (0x%x)", attr->recursive); + return CELL_EINVAL; + } + + const u32 protocol = attr->protocol; + + switch (protocol) + { + case SYS_SYNC_FIFO: break; + case SYS_SYNC_RETRY: break; + case SYS_SYNC_PRIORITY: break; + default: sysPrxForUser.Error("sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL; + } + + std::shared_ptr lw(new lwmutex_t(protocol, attr->name_u64)); + + lwmutex->lock_var.write_relaxed({ lwmutex::free, lwmutex::zero }); + lwmutex->attribute = attr->recursive | attr->protocol; + lwmutex->recursive_count = 0; + lwmutex->sleep_queue = Emu.GetIdManager().GetNewID(lw); + + return CELL_OK; +} + +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Warning("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); + + // check to prevent recursive locking in the next call + if (lwmutex->lock_var.read_relaxed().owner == CPU.GetId()) + { + return CELL_EBUSY; + } + + // attempt to lock the mutex + if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) + { + return res; + } + + // call the syscall + if (s32 res = _sys_lwmutex_destroy(CPU, lwmutex->sleep_queue)) + { + // unlock the mutex if failed + sys_lwmutex_unlock(CPU, lwmutex); + + return res; + } + + // deleting succeeded + lwmutex->owner.exchange(lwmutex::dead); + + return CELL_OK; +} + +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) +{ + sysPrxForUser.Log("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); + + const be_t tid = be_t::make(CPU.GetId()); + + // try to lock lightweight mutex + const be_t old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid); + + if (old_owner.data() == se32(lwmutex_free)) + { + // locking succeeded + return CELL_OK; + } + + if (old_owner.data() == tid.data()) + { + // recursive locking + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0) + { + // if not recursive + return CELL_EDEADLK; + } + + if (lwmutex->recursive_count.data() == -1) + { + // if recursion limit reached + return CELL_EKRESOURCE; + } + + // recursive locking succeeded + lwmutex->recursive_count++; + lwmutex->lock_var.read_sync(); + + return CELL_OK; + } + + if (old_owner.data() == se32(lwmutex_dead)) + { + // invalid or deleted mutex + return CELL_EINVAL; + } + + for (u32 i = 0; i < 300; i++) + { + if (lwmutex->owner.read_relaxed().data() == se32(lwmutex_free)) + { + if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) + { + // locking succeeded + return CELL_OK; + } + } + } + + lwmutex->waiter.atomic_op([](be_t& value){ value++; }); + + if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) + { + // locking succeeded + lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + + return CELL_OK; + } + + // lock using the syscall + const s32 res = _sys_lwmutex_lock(CPU, lwmutex->sleep_queue, timeout); + + lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + + if (res == CELL_OK) + { + // locking succeeded + lwmutex->owner.exchange(tid); + + return CELL_OK; + } + + if (res == CELL_EBUSY && lwmutex->attribute.data() & se32(SYS_SYNC_RETRY)) + { + // TODO (protocol is ignored in current implementation) + throw __FUNCTION__; + } + + return res; +} + +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Log("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); + + const be_t tid = be_t::make(CPU.GetId()); + + // try to lock lightweight mutex + const be_t old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid); + + if (old_owner.data() == se32(lwmutex_free)) + { + // locking succeeded + return CELL_OK; + } + + if (old_owner.data() == tid.data()) + { + // recursive locking + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0) + { + // if not recursive + return CELL_EDEADLK; + } + + if (lwmutex->recursive_count.data() == -1) + { + // if recursion limit reached + return CELL_EKRESOURCE; + } + + // recursive locking succeeded + lwmutex->recursive_count++; + lwmutex->lock_var.read_sync(); + + return CELL_OK; + } + + if (old_owner.data() == se32(lwmutex_dead)) + { + // invalid or deleted mutex + return CELL_EINVAL; + } + + if (old_owner.data() == se32(lwmutex_busy)) + { + // should be locked by the syscall + const s32 res = _sys_lwmutex_trylock(CPU, lwmutex->sleep_queue); + + if (res == CELL_OK) + { + // locking succeeded + lwmutex->owner.exchange(tid); + } + + return res; + } + + // locked by another thread + return CELL_EBUSY; +} + +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); + + const be_t tid = be_t::make(CPU.GetId()); + + // check owner + if (lwmutex->owner.read_relaxed() != tid) + { + return CELL_EPERM; + } + + if (lwmutex->recursive_count.data()) + { + // recursive unlocking succeeded + lwmutex->recursive_count--; + + return CELL_OK; + } + + // ensure that waiter is zero + if (lwmutex->lock_var.compare_and_swap_test({ tid, lwmutex::zero }, { lwmutex::free, lwmutex::zero })) + { + // unlocking succeeded + return CELL_OK; + } + + if (lwmutex->attribute.data() & se32(SYS_SYNC_RETRY)) + { + // TODO (protocol is ignored in current implementation) + } + + lwmutex->owner.exchange(lwmutex::busy); + + // call the syscall + if (_sys_lwmutex_unlock(CPU, lwmutex->sleep_queue) == CELL_ESRCH) + { + return CELL_ESRCH; + } + + return CELL_OK; +} + std::string ps3_fmt(PPUThread& context, vm::ptr fmt, u32 g_count, u32 f_count, u32 v_count) { std::string result; @@ -575,6 +832,59 @@ s32 sys_process_get_paramsfo(vm::ptr buffer) return _sys_process_get_paramsfo(buffer); } +void sys_spinlock_initialize(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_initialize(lock=*0x%x)", lock); + + // prx: set 0 and sync + lock->exchange(be_t::make(0)); +} + +void sys_spinlock_lock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_lock(lock=*0x%x)", lock); + + // prx: exchange with 0xabadcafe, repeat until exchanged with 0 + while (lock->exchange(be_t::make(0xabadcafe)).data()) + { + while (lock->read_relaxed().data()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + if (Emu.IsStopped()) + { + break; + } + } + + if (Emu.IsStopped()) + { + sysPrxForUser.Warning("sys_spinlock_lock(lock=*0x%x) aborted", lock); + break; + } + } +} + +s32 sys_spinlock_trylock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_trylock(lock=*0x%x)", lock); + + // prx: exchange with 0xabadcafe, translate exchanged value + if (lock->exchange(be_t::make(0xabadcafe)).data()) + { + return CELL_EBUSY; + } + + return CELL_OK; +} + +void sys_spinlock_unlock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_unlock(lock=*0x%x)", lock); + + // prx: sync and set 0 + lock->exchange(be_t::make(0)); +} + Module sysPrxForUser("sysPrxForUser", []() { g_tls_start = 0; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h index 76234c5c4b..7a461b06e5 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h @@ -22,5 +22,14 @@ extern vm::ptr spu_printf_dgcb; extern vm::ptr spu_printf_atcb; extern vm::ptr spu_printf_dtcb; -// SysCalls +// Functions vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size); + +struct sys_lwmutex_t; +struct sys_lwmutex_attribute_t; + +s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index be5b11b94d..55dd25915a 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -108,7 +108,7 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_timer_create), //70 (0x046) bind_func(sys_timer_destroy), //71 (0x047) bind_func(sys_timer_get_information), //72 (0x048) - bind_func(_sys_timer_start), //73 (0x049) + bind_func(_sys_timer_start), //73 (0x049) bind_func(sys_timer_stop), //74 (0x04A) bind_func(sys_timer_connect_event_queue), //75 (0x04B) bind_func(sys_timer_disconnect_event_queue), //76 (0x04C) @@ -124,17 +124,17 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_event_flag_trywait), //86 (0x056) bind_func(sys_event_flag_set), //87 (0x057) bind_func(sys_interrupt_thread_eoi), //88 (0x058) - bind_func(_sys_interrupt_thread_disestablish), //89 (0x059) + bind_func(_sys_interrupt_thread_disestablish), //89 (0x059) bind_func(sys_semaphore_create), //90 (0x05A) bind_func(sys_semaphore_destroy), //91 (0x05B) bind_func(sys_semaphore_wait), //92 (0x05C) bind_func(sys_semaphore_trywait), //93 (0x05D) bind_func(sys_semaphore_post), //94 (0x05E) - null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create - null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy - null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock - null_func,//bind_func(_sys_lwmutex_???lock), //98 (0x062) // internal, used by sys_lwmutex_unlock - null_func,//bind_func(_sys_lwmutex_???lock), //99 (0x063) // internal, used by sys_lwmutex_trylock + bind_func(_sys_lwmutex_create), //95 (0x05F) + bind_func(_sys_lwmutex_destroy), //96 (0x060) + bind_func(_sys_lwmutex_lock), //97 (0x061) + bind_func(_sys_lwmutex_unlock), //98 (0x062) + bind_func(_sys_lwmutex_trylock), //99 (0x063) bind_func(sys_mutex_create), //100 (0x064) bind_func(sys_mutex_destroy), //101 (0x065) bind_func(sys_mutex_lock), //102 (0x066) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index cf0182a43f..5ee5c0c34e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -5,6 +5,7 @@ #include "Emu/SysCalls/SysCalls.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/SysCalls/Modules/sysPrxForUser.h" #include "sleep_queue.h" #include "sys_time.h" #include "sys_lwmutex.h" @@ -159,8 +160,8 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) lw->queue.push(tid_le, mutex->attribute); - auto old_recursive = mutex->recursive_count.read_relaxed(); - mutex->recursive_count.exchange(be_t::make(0)); + auto old_recursive = mutex->recursive_count; + mutex->recursive_count = 0; auto target = be_t::make(sq->signal(mutex->attribute)); if (!mutex->owner.compare_and_swap_test(tid, target)) @@ -173,7 +174,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) { if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads { - s32 res = mutex->lock(tid, timeout ? get_system_time() - start_time : 0); // this is bad + s32 res = sys_lwmutex_lock(CPU, mutex, timeout ? get_system_time() - start_time : 0); // this is bad if (res == CELL_OK) { break; @@ -226,6 +227,6 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) } } - mutex->recursive_count.exchange(old_recursive); + mutex->recursive_count = old_recursive; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 319fe29466..3336574681 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -12,210 +12,37 @@ SysCallBase sys_lwmutex("sys_lwmutex"); -s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) +void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name) { - std::shared_ptr sq(new sleep_queue_t(name_u64)); + std::shared_ptr lw(new lwmutex_t(protocol, name)); - lwmutex.owner.write_relaxed(be_t::make(0)); - lwmutex.waiter.write_relaxed(be_t::make(~0)); - lwmutex.attribute = protocol | recursive; - lwmutex.recursive_count.write_relaxed(be_t::make(0)); - u32 sq_id = Emu.GetIdManager().GetNewID(sq, TYPE_LWMUTEX); - lwmutex.sleep_queue = sq_id; - sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, vm::get_addr(&lwmutex))); - - // passing be_t (test) - sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), lwmutex.attribute, sq_id); - return CELL_OK; + lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero }); + lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE); + lwmutex.recursive_count = 0; + lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(lw, TYPE_LWMUTEX); } -s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr) +s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6) { - sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); - - switch (attr->recursive.data()) - { - case se32(SYS_SYNC_RECURSIVE): break; - case se32(SYS_SYNC_NOT_RECURSIVE): break; - default: sys_lwmutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL; - } - - switch (attr->protocol.data()) - { - case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): break; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; - case se32(SYS_SYNC_FIFO): break; - default: sys_lwmutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; - } - - return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64); + throw __FUNCTION__; } -s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); - - u32 sq_id = lwmutex->sleep_queue; - if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH; - - if (s32 res = lwmutex->trylock(be_t::make(~0))) - { - return res; - } - - // try to make it unable to lock - lwmutex->all_info() = 0; - lwmutex->attribute = 0xDEADBEEF; - lwmutex->sleep_queue = 0; - Emu.GetIdManager().RemoveID(sq_id); - return CELL_OK; + throw __FUNCTION__; } -s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) +s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout) { - sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout); - - return lwmutex->lock(be_t::make(CPU.GetId()), timeout); + throw __FUNCTION__; } -s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr()); - - return lwmutex->trylock(be_t::make(CPU.GetId())); + throw __FUNCTION__; } -s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr()); - - return lwmutex->unlock(be_t::make(CPU.GetId())); -} - -s32 sys_lwmutex_t::trylock(be_t tid) -{ - if (attribute.data() == se32(0xDEADBEEF)) - { - return CELL_EINVAL; - } - - if (!Emu.GetIdManager().CheckID(sleep_queue)) - { - return CELL_ESRCH; - } - - const be_t old_owner = owner.read_sync(); - - if (old_owner == tid) - { - if (attribute.data() & se32(SYS_SYNC_RECURSIVE)) - { - auto rv = recursive_count.read_relaxed(); - if (!~(rv++).data()) - { - return CELL_EKRESOURCE; - } - - recursive_count.exchange(rv); - return CELL_OK; - } - else - { - return CELL_EDEADLK; - } - } - - if (!owner.compare_and_swap_test(be_t::make(0), tid)) - { - return CELL_EBUSY; - } - - recursive_count.exchange(be_t::make(1)); - return CELL_OK; -} - -s32 sys_lwmutex_t::unlock(be_t tid) -{ - if (owner.read_sync() != tid) - { - return CELL_EPERM; - } - - auto rv = recursive_count.read_relaxed(); - if (!rv.data() || (rv.data() != se32(1) && (attribute.data() & se32(SYS_SYNC_NOT_RECURSIVE)))) - { - sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv); - rv = 1; - } - - rv--; - recursive_count.exchange(rv); - if (!rv.data()) - { - std::shared_ptr sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) - { - return CELL_ESRCH; - } - - if (!owner.compare_and_swap_test(tid, be_t::make(sq->signal(attribute)))) - { - assert(!"sys_lwmutex_t::unlock() failed"); - } - } - - return CELL_OK; -} - -s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) -{ - const u64 start_time = get_system_time(); - - switch (s32 res = trylock(tid)) - { - case static_cast(CELL_EBUSY): break; - default: return res; - } - - std::shared_ptr sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) - { - return CELL_ESRCH; - } - - sq->push(tid, attribute); - - while (true) - { - auto old_owner = owner.compare_and_swap(be_t::make(0), tid); - if (!old_owner.data() || old_owner == tid) - { - break; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - - if (timeout && get_system_time() - start_time > timeout) - { - if (!sq->invalidate(tid, attribute)) - { - assert(!"sys_lwmutex_t::lock() failed (timeout)"); - } - return CELL_ETIMEDOUT; - } - - if (Emu.IsStopped()) - { - sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); - return CELL_OK; - } - } - - if (!sq->invalidate(tid, attribute) && !sq->pop(tid, attribute)) - { - assert(!"sys_lwmutex_t::lock() failed (locking)"); - } - recursive_count.exchange(be_t::make(1)); - return CELL_OK; + throw __FUNCTION__; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index ce29524d48..7f76a4c8a2 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -4,6 +4,7 @@ struct sys_lwmutex_attribute_t { be_t protocol; be_t recursive; + union { char name[8]; @@ -11,33 +12,78 @@ struct sys_lwmutex_attribute_t }; }; +enum : u32 +{ + lwmutex_zero = 0u, + lwmutex_free = 0u - 1u, + lwmutex_dead = 0u - 2u, + lwmutex_busy = 0u - 3u, +}; + +namespace lwmutex +{ + template + struct const_be_u32_t + { + static const u32 value = _value; + + operator const be_t() const + { + return be_t::make(value); + } + }; + + static const_be_u32_t zero; + static const_be_u32_t free; + static const_be_u32_t dead; + static const_be_u32_t busy; +} + struct sys_lwmutex_t { - atomic_t owner; - atomic_t waiter; // currently not used - be_t attribute; - atomic_t recursive_count; - be_t sleep_queue; - be_t pad; - - u64& all_info() + struct sync_var_t { - return *(reinterpret_cast(this)); - } + be_t owner; + be_t waiter; + }; - s32 trylock(be_t tid); - s32 unlock(be_t tid); - s32 lock(be_t tid, u64 timeout); + union + { + atomic_t lock_var; + + struct + { + atomic_t owner; + atomic_t waiter; + }; + }; + + be_t attribute; + be_t recursive_count; + be_t sleep_queue; // lwmutex pseudo-id + be_t pad; +}; + +struct lwmutex_t +{ + const u32 protocol; + const u64 name; + + lwmutex_t(u32 protocol, u64 name) + : protocol(protocol) + , name(name) + { + } }; // Aux -s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); +void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name); class PPUThread; // SysCalls -s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); -s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); +s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6); +s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id); +s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout); +s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id); +s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp deleted file mode 100644 index e7ec98dc93..0000000000 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "sys_spinlock.h" - -SysCallBase sys_spinlock("sys_spinlock"); - -void sys_spinlock_initialize(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_initialize(lock_addr=0x%x)", lock.addr()); - - // prx: set 0 and sync - lock->exchange(be_t::make(0)); -} - -void sys_spinlock_lock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.addr()); - - // prx: exchange with 0xabadcafe, repeat until exchanged with 0 - while (lock->exchange(be_t::make(0xabadcafe)).data()) - { - while (lock->read_relaxed().data()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - break; - } - } - - if (Emu.IsStopped()) - { - sys_spinlock.Warning("sys_spinlock_lock(0x%x) aborted", lock.addr()); - break; - } - } -} - -s32 sys_spinlock_trylock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.addr()); - - // prx: exchange with 0xabadcafe, translate exchanged value - if (lock->exchange(be_t::make(0xabadcafe)).data()) - { - return CELL_EBUSY; - } - - return CELL_OK; -} - -void sys_spinlock_unlock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.addr()); - - // prx: sync and set 0 - lock->exchange(be_t::make(0)); -} diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h deleted file mode 100644 index 42a2bb5a6c..0000000000 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -// SysCalls -void sys_spinlock_initialize(vm::ptr> lock); -void sys_spinlock_lock(vm::ptr> lock); -s32 sys_spinlock_trylock(vm::ptr> lock); -void sys_spinlock_unlock(vm::ptr> lock); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index c3d5e90d0e..d0f086572f 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -194,7 +194,6 @@ - @@ -457,7 +456,6 @@ - diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 0d0905572a..c1fa6b8ea9 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -512,9 +512,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Emu\SysCalls\lv2 @@ -1282,9 +1279,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Emu\SysCalls\lv2