mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 20:22:30 +01:00
Lv2 lwmutex "true" syscalls experimentally implemented
This commit is contained in:
parent
507798c541
commit
8155ef5e67
@ -139,7 +139,7 @@ s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// call the syscall
|
// call the syscall
|
||||||
if (s32 res = _sys_lwmutex_destroy(CPU, lwmutex->sleep_queue))
|
if (s32 res = _sys_lwmutex_destroy(lwmutex->sleep_queue))
|
||||||
{
|
{
|
||||||
// unlock the mutex if failed
|
// unlock the mutex if failed
|
||||||
sys_lwmutex_unlock(CPU, lwmutex);
|
sys_lwmutex_unlock(CPU, lwmutex);
|
||||||
@ -209,20 +209,21 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lwmutex->waiter.atomic_op([](be_t<u32>& value){ value++; });
|
// atomically increment waiter value using 64 bit op
|
||||||
|
lwmutex->all_info.atomic_op([](be_t<u64>& value){ value++; });
|
||||||
|
|
||||||
if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid))
|
if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid))
|
||||||
{
|
{
|
||||||
// locking succeeded
|
// locking succeeded
|
||||||
lwmutex->waiter.atomic_op([](be_t<u32>& value){ value--; });
|
lwmutex->all_info.atomic_op([](be_t<u64>& value){ value--; });
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lock using the syscall
|
// lock using the syscall
|
||||||
const s32 res = _sys_lwmutex_lock(CPU, lwmutex->sleep_queue, timeout);
|
const s32 res = _sys_lwmutex_lock(lwmutex->sleep_queue, timeout);
|
||||||
|
|
||||||
lwmutex->waiter.atomic_op([](be_t<u32>& value){ value--; });
|
lwmutex->all_info.atomic_op([](be_t<u64>& value){ value--; });
|
||||||
|
|
||||||
if (res == CELL_OK)
|
if (res == CELL_OK)
|
||||||
{
|
{
|
||||||
@ -285,10 +286,10 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
|||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_owner.data() == se32(lwmutex_busy))
|
if (old_owner.data() == se32(lwmutex_reserved))
|
||||||
{
|
{
|
||||||
// should be locked by the syscall
|
// should be locked by the syscall
|
||||||
const s32 res = _sys_lwmutex_trylock(CPU, lwmutex->sleep_queue);
|
const s32 res = _sys_lwmutex_trylock(lwmutex->sleep_queue);
|
||||||
|
|
||||||
if (res == CELL_OK)
|
if (res == CELL_OK)
|
||||||
{
|
{
|
||||||
@ -335,10 +336,11 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
|||||||
// TODO (protocol is ignored in current implementation)
|
// TODO (protocol is ignored in current implementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
lwmutex->owner.exchange(lwmutex::busy);
|
// set special value
|
||||||
|
lwmutex->owner.exchange(lwmutex::reserved);
|
||||||
|
|
||||||
// call the syscall
|
// call the syscall
|
||||||
if (_sys_lwmutex_unlock(CPU, lwmutex->sleep_queue) == CELL_ESRCH)
|
if (_sys_lwmutex_unlock(lwmutex->sleep_queue) == CELL_ESRCH)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
@ -14,35 +14,137 @@ SysCallBase sys_lwmutex("sys_lwmutex");
|
|||||||
|
|
||||||
void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name)
|
void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name)
|
||||||
{
|
{
|
||||||
std::shared_ptr<lwmutex_t> lw(new lwmutex_t(protocol, name));
|
std::shared_ptr<lwmutex_t> mutex(new lwmutex_t(protocol, name));
|
||||||
|
|
||||||
lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero });
|
lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero });
|
||||||
lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE);
|
lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE);
|
||||||
lwmutex.recursive_count = 0;
|
lwmutex.recursive_count = 0;
|
||||||
lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(lw, TYPE_LWMUTEX);
|
lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(mutex, TYPE_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_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> control, u32 arg4, u64 name, u32 arg6)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sys_lwmutex.Warning("_sys_lwmutex_create(lwmutex_id=*0x%x, protocol=0x%x, control=*0x%x, arg4=0x%x, name=0x%llx, arg6=0x%x)", lwmutex_id, protocol, control, arg4, name, arg6);
|
||||||
|
|
||||||
|
switch (protocol)
|
||||||
|
{
|
||||||
|
case SYS_SYNC_FIFO: break;
|
||||||
|
case SYS_SYNC_RETRY: break;
|
||||||
|
case SYS_SYNC_PRIORITY: break;
|
||||||
|
default: sys_lwmutex.Error("_sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg4 != 0x80000001 || arg6)
|
||||||
|
{
|
||||||
|
sys_lwmutex.Error("_sys_lwmutex_create(): unknown parameters (arg4=0x%x, arg6=0x%x)", arg4, arg6);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<lwmutex_t> mutex(new lwmutex_t(protocol, name));
|
||||||
|
|
||||||
|
*lwmutex_id = Emu.GetIdManager().GetNewID(mutex, TYPE_LWMUTEX);
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id)
|
s32 _sys_lwmutex_destroy(u32 lwmutex_id)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sys_lwmutex.Warning("_sys_lwmutex_destroy(lwmutex_id=%d)", lwmutex_id);
|
||||||
|
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
|
std::shared_ptr<lwmutex_t> mutex;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex->waiters)
|
||||||
|
{
|
||||||
|
return CELL_EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emu.GetIdManager().RemoveID(lwmutex_id);
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout)
|
s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sys_lwmutex.Log("_sys_lwmutex_lock(lwmutex_id=%d, timeout=0x%llx)", lwmutex_id, timeout);
|
||||||
|
|
||||||
|
const u64 start_time = get_system_time();
|
||||||
|
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
|
std::shared_ptr<lwmutex_t> mutex;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// protocol is ignored in current implementation
|
||||||
|
mutex->waiters++; assert(mutex->waiters > 0);
|
||||||
|
|
||||||
|
while (!mutex->signals)
|
||||||
|
{
|
||||||
|
if (timeout && get_system_time() - start_time > timeout)
|
||||||
|
{
|
||||||
|
mutex->waiters--; assert(mutex->waiters >= 0);
|
||||||
|
return CELL_ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
sys_lwmutex.Warning("_sys_lwmutex_lock(lwmutex_id=%d) aborted", lwmutex_id);
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex->signals--;
|
||||||
|
|
||||||
|
mutex->waiters--; assert(mutex->waiters >= 0);
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id)
|
s32 _sys_lwmutex_trylock(u32 lwmutex_id)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sys_lwmutex.Log("_sys_lwmutex_trylock(lwmutex_id=%d)", lwmutex_id);
|
||||||
|
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
|
std::shared_ptr<lwmutex_t> mutex;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex->waiters || !mutex->signals)
|
||||||
|
{
|
||||||
|
return CELL_EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex->signals--;
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id)
|
s32 _sys_lwmutex_unlock(u32 lwmutex_id)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sys_lwmutex.Log("_sys_lwmutex_unlock(lwmutex_id=%d)", lwmutex_id);
|
||||||
|
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
|
std::shared_ptr<lwmutex_t> mutex;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex->signals++;
|
||||||
|
mutex->cv.notify_one();
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@ struct sys_lwmutex_attribute_t
|
|||||||
|
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
lwmutex_zero = 0u,
|
lwmutex_zero = 0u,
|
||||||
lwmutex_free = 0u - 1u,
|
lwmutex_free = 0u - 1u,
|
||||||
lwmutex_dead = 0u - 2u,
|
lwmutex_dead = 0u - 2u,
|
||||||
lwmutex_busy = 0u - 3u,
|
lwmutex_reserved = 0u - 3u,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace lwmutex
|
namespace lwmutex
|
||||||
@ -36,7 +36,7 @@ namespace lwmutex
|
|||||||
static const_be_u32_t<lwmutex_zero> zero;
|
static const_be_u32_t<lwmutex_zero> zero;
|
||||||
static const_be_u32_t<lwmutex_free> free;
|
static const_be_u32_t<lwmutex_free> free;
|
||||||
static const_be_u32_t<lwmutex_dead> dead;
|
static const_be_u32_t<lwmutex_dead> dead;
|
||||||
static const_be_u32_t<lwmutex_busy> busy;
|
static const_be_u32_t<lwmutex_reserved> reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sys_lwmutex_t
|
struct sys_lwmutex_t
|
||||||
@ -56,6 +56,8 @@ struct sys_lwmutex_t
|
|||||||
atomic_t<u32> owner;
|
atomic_t<u32> owner;
|
||||||
atomic_t<u32> waiter;
|
atomic_t<u32> waiter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
atomic_t<u64> all_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
be_t<u32> attribute;
|
be_t<u32> attribute;
|
||||||
@ -69,6 +71,13 @@ struct lwmutex_t
|
|||||||
const u32 protocol;
|
const u32 protocol;
|
||||||
const u64 name;
|
const u64 name;
|
||||||
|
|
||||||
|
// this object is not truly a mutex and its syscall names are wrong, it's probabably sleep queue or something
|
||||||
|
std::atomic<u32> signals;
|
||||||
|
|
||||||
|
// TODO: use sleep queue, possibly remove condition variable
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::atomic<s32> waiters;
|
||||||
|
|
||||||
lwmutex_t(u32 protocol, u64 name)
|
lwmutex_t(u32 protocol, u64 name)
|
||||||
: protocol(protocol)
|
: protocol(protocol)
|
||||||
, name(name)
|
, name(name)
|
||||||
@ -83,7 +92,7 @@ class PPUThread;
|
|||||||
|
|
||||||
// SysCalls
|
// SysCalls
|
||||||
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_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_destroy(u32 lwmutex_id);
|
||||||
s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout);
|
s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout);
|
||||||
s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id);
|
s32 _sys_lwmutex_trylock(u32 lwmutex_id);
|
||||||
s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id);
|
s32 _sys_lwmutex_unlock(u32 lwmutex_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user