1
0
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:
Nekotekina 2015-03-09 04:30:34 +03:00
parent 507798c541
commit 8155ef5e67
3 changed files with 142 additions and 29 deletions

View File

@ -139,7 +139,7 @@ s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
}
// 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
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))
{
// locking succeeded
lwmutex->waiter.atomic_op([](be_t<u32>& value){ value--; });
lwmutex->all_info.atomic_op([](be_t<u64>& value){ value--; });
return CELL_OK;
}
// 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)
{
@ -285,10 +286,10 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
return CELL_EINVAL;
}
if (old_owner.data() == se32(lwmutex_busy))
if (old_owner.data() == se32(lwmutex_reserved))
{
// 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)
{
@ -335,10 +336,11 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
// TODO (protocol is ignored in current implementation)
}
lwmutex->owner.exchange(lwmutex::busy);
// set special value
lwmutex->owner.exchange(lwmutex::reserved);
// 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;
}

View File

@ -14,35 +14,137 @@ SysCallBase sys_lwmutex("sys_lwmutex");
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.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE);
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)
{
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;
}

View File

@ -14,10 +14,10 @@ struct sys_lwmutex_attribute_t
enum : u32
{
lwmutex_zero = 0u,
lwmutex_free = 0u - 1u,
lwmutex_dead = 0u - 2u,
lwmutex_busy = 0u - 3u,
lwmutex_zero = 0u,
lwmutex_free = 0u - 1u,
lwmutex_dead = 0u - 2u,
lwmutex_reserved = 0u - 3u,
};
namespace lwmutex
@ -36,7 +36,7 @@ namespace lwmutex
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;
static const_be_u32_t<lwmutex_reserved> reserved;
}
struct sys_lwmutex_t
@ -56,6 +56,8 @@ struct sys_lwmutex_t
atomic_t<u32> owner;
atomic_t<u32> waiter;
};
atomic_t<u64> all_info;
};
be_t<u32> attribute;
@ -69,6 +71,13 @@ struct lwmutex_t
const u32 protocol;
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)
: protocol(protocol)
, name(name)
@ -83,7 +92,7 @@ class PPUThread;
// 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_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);
s32 _sys_lwmutex_destroy(u32 lwmutex_id);
s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout);
s32 _sys_lwmutex_trylock(u32 lwmutex_id);
s32 _sys_lwmutex_unlock(u32 lwmutex_id);