mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-22 12:35:21 +00:00
Lv2 Lwmutex
This commit is contained in:
parent
9883e1e8b8
commit
507798c541
11 changed files with 416 additions and 301 deletions
|
@ -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");
|
||||
|
|
|
@ -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<std::atomic<u32>, 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<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> 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<lwmutex_t> 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<sys_lwmutex_t> 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<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
// try to lock lightweight mutex
|
||||
const be_t<u32> 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<u32>& value){ value++; });
|
||||
|
||||
if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid))
|
||||
{
|
||||
// locking succeeded
|
||||
lwmutex->waiter.atomic_op([](be_t<u32>& 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<u32>& 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<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
// try to lock lightweight mutex
|
||||
const be_t<u32> 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<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::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<const char> fmt, u32 g_count, u32 f_count, u32 v_count)
|
||||
{
|
||||
std::string result;
|
||||
|
@ -575,6 +832,59 @@ s32 sys_process_get_paramsfo(vm::ptr<char> buffer)
|
|||
return _sys_process_get_paramsfo(buffer);
|
||||
}
|
||||
|
||||
void sys_spinlock_initialize(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_initialize(lock=*0x%x)", lock);
|
||||
|
||||
// prx: set 0 and sync
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
||||
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_lock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: exchange with 0xabadcafe, repeat until exchanged with 0
|
||||
while (lock->exchange(be_t<u32>::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<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_trylock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: exchange with 0xabadcafe, translate exchanged value
|
||||
if (lock->exchange(be_t<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_unlock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: sync and set 0
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
||||
|
||||
Module sysPrxForUser("sysPrxForUser", []()
|
||||
{
|
||||
g_tls_start = 0;
|
||||
|
|
|
@ -22,5 +22,14 @@ extern vm::ptr<spu_printf_cb_t> spu_printf_dgcb;
|
|||
extern vm::ptr<spu_printf_cb_t> spu_printf_atcb;
|
||||
extern vm::ptr<spu_printf_cb_t> spu_printf_dtcb;
|
||||
|
||||
// SysCalls
|
||||
// Functions
|
||||
vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size);
|
||||
|
||||
struct sys_lwmutex_t;
|
||||
struct sys_lwmutex_attribute_t;
|
||||
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<sys_lwcond_t> lwcond, u64 timeout)
|
|||
|
||||
lw->queue.push(tid_le, mutex->attribute);
|
||||
|
||||
auto old_recursive = mutex->recursive_count.read_relaxed();
|
||||
mutex->recursive_count.exchange(be_t<u32>::make(0));
|
||||
auto old_recursive = mutex->recursive_count;
|
||||
mutex->recursive_count = 0;
|
||||
|
||||
auto target = be_t<u32>::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<sys_lwcond_t> 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<sys_lwcond_t> lwcond, u64 timeout)
|
|||
}
|
||||
}
|
||||
|
||||
mutex->recursive_count.exchange(old_recursive);
|
||||
mutex->recursive_count = old_recursive;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
|
@ -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<sleep_queue_t> sq(new sleep_queue_t(name_u64));
|
||||
std::shared_ptr<lwmutex_t> lw(new lwmutex_t(protocol, name));
|
||||
|
||||
lwmutex.owner.write_relaxed(be_t<u32>::make(0));
|
||||
lwmutex.waiter.write_relaxed(be_t<u32>::make(~0));
|
||||
lwmutex.attribute = protocol | recursive;
|
||||
lwmutex.recursive_count.write_relaxed(be_t<u32>::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<u32> (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<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
||||
s32 _sys_lwmutex_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> 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<sys_lwmutex_t> 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<u32>::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<sys_lwmutex_t> 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<u32>::make(CPU.GetId()), timeout);
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> 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<u32>::make(CPU.GetId()));
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> 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<u32>::make(CPU.GetId()));
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::trylock(be_t<u32> tid)
|
||||
{
|
||||
if (attribute.data() == se32(0xDEADBEEF))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(sleep_queue))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
const be_t<u32> 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<u32>::make(0), tid))
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
recursive_count.exchange(be_t<u32>::make(1));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::unlock(be_t<u32> 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<sleep_queue_t> sq;
|
||||
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!owner.compare_and_swap_test(tid, be_t<u32>::make(sq->signal(attribute))))
|
||||
{
|
||||
assert(!"sys_lwmutex_t::unlock() failed");
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
|
||||
{
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
switch (s32 res = trylock(tid))
|
||||
{
|
||||
case static_cast<s32>(CELL_EBUSY): break;
|
||||
default: return res;
|
||||
}
|
||||
|
||||
std::shared_ptr<sleep_queue_t> 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<u32>::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<u32>::make(1));
|
||||
return CELL_OK;
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ struct sys_lwmutex_attribute_t
|
|||
{
|
||||
be_t<u32> protocol;
|
||||
be_t<u32> 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<u32 _value>
|
||||
struct const_be_u32_t
|
||||
{
|
||||
static const u32 value = _value;
|
||||
|
||||
operator const be_t<u32>() const
|
||||
{
|
||||
return be_t<u32>::make(value);
|
||||
}
|
||||
};
|
||||
|
||||
static const_be_u32_t<lwmutex_zero> zero;
|
||||
static const_be_u32_t<lwmutex_free> free;
|
||||
static const_be_u32_t<lwmutex_dead> dead;
|
||||
static const_be_u32_t<lwmutex_busy> busy;
|
||||
}
|
||||
|
||||
struct sys_lwmutex_t
|
||||
{
|
||||
atomic_t<u32> owner;
|
||||
atomic_t<u32> waiter; // currently not used
|
||||
be_t<u32> attribute;
|
||||
atomic_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue;
|
||||
be_t<u32> pad;
|
||||
|
||||
u64& all_info()
|
||||
struct sync_var_t
|
||||
{
|
||||
return *(reinterpret_cast<u64*>(this));
|
||||
}
|
||||
be_t<u32> owner;
|
||||
be_t<u32> waiter;
|
||||
};
|
||||
|
||||
s32 trylock(be_t<u32> tid);
|
||||
s32 unlock(be_t<u32> tid);
|
||||
s32 lock(be_t<u32> tid, u64 timeout);
|
||||
union
|
||||
{
|
||||
atomic_t<sync_var_t> lock_var;
|
||||
|
||||
struct
|
||||
{
|
||||
atomic_t<u32> owner;
|
||||
atomic_t<u32> waiter;
|
||||
};
|
||||
};
|
||||
|
||||
be_t<u32> attribute;
|
||||
be_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue; // lwmutex pseudo-id
|
||||
be_t<u32> 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<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 _sys_lwmutex_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> 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);
|
||||
|
|
|
@ -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<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_initialize(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: set 0 and sync
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
||||
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> 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<u32>::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<atomic_t<u32>> 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<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: sync and set 0
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// SysCalls
|
||||
void sys_spinlock_initialize(vm::ptr<atomic_t<u32>> lock);
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> lock);
|
||||
s32 sys_spinlock_trylock(vm::ptr<atomic_t<u32>> lock);
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock);
|
|
@ -194,7 +194,6 @@
|
|||
<ClCompile Include="Emu\SysCalls\lv2\sys_rsx.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_rwlock.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_semaphore.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spinlock.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spu.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_time.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_timer.cpp" />
|
||||
|
@ -457,7 +456,6 @@
|
|||
<ClInclude Include="Emu\SysCalls\lv2\sys_rsx.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_rwlock.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_semaphore.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spinlock.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spu.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_time.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_timer.h" />
|
||||
|
|
|
@ -512,9 +512,6 @@
|
|||
<ClCompile Include="Emu\SysCalls\lv2\sys_rsx.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spinlock.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_ppu_thread.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1282,9 +1279,6 @@
|
|||
<ClInclude Include="Emu\SysCalls\lv2\sys_rsx.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spinlock.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_ppu_thread.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Add table
Reference in a new issue