rpcsx/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp

130 lines
3.2 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
2014-01-19 22:19:37 +01:00
#include "Emu/SysCalls/lv2/SC_Lwmutex.h"
#include <mutex>
2014-01-19 22:19:37 +01:00
SysCallBase sc_lwmutex("sys_lwmutex");
2014-01-19 22:19:37 +01:00
std::mutex g_lwmutex;
2014-01-19 22:19:37 +01:00
int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_t> attr)
{
sc_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)",
2014-01-19 22:19:37 +01:00
lwmutex.GetAddr(), attr.GetAddr());
2014-01-19 22:19:37 +01:00
if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
2014-01-19 22:19:37 +01:00
switch ((u32)attr->attr_recursive)
{
2014-01-19 22:19:37 +01:00
case SYS_SYNC_RECURSIVE: break;
case SYS_SYNC_NOT_RECURSIVE: break;
default: return CELL_EINVAL;
}
2014-01-19 22:19:37 +01:00
switch ((u32)attr->attr_protocol)
{
case SYS_SYNC_PRIORITY: sc_lwmutex.Warning("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.Warning("TODO: SYS_SYNC_FIFO attr"); break;
2014-01-19 22:19:37 +01:00
default: return CELL_EINVAL;
}
lwmutex->attribute = (u32)attr->attr_protocol | (u32)attr->attr_recursive;
lwmutex->all_info = 0;
lwmutex->pad = 0;
lwmutex->recursive_count = 0;
lwmutex->sleep_queue = 0;
2014-01-31 22:35:48 +01:00
sc_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): id=???", attr->name, (u32)lwmutex->attribute);
return CELL_OK;
}
2014-01-19 22:19:37 +01:00
int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
{
sc_lwmutex.Warning("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<std::mutex> lock(g_lwmutex);
if (!lwmutex->owner)
{
lwmutex->owner = ~0; // make it unable to lock
lwmutex->attribute = 0;
}
else
{
return CELL_EBUSY;
}
}
return CELL_OK;
}
2014-01-19 22:19:37 +01:00
int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
{
sc_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout);
2014-01-19 22:19:37 +01:00
if (!lwmutex.IsGood()) return CELL_EFAULT;
if (!lwmutex->attribute) return CELL_EINVAL;
const u32 tid = GetCurrentPPUThread().GetId();
int res = lwmutex->trylock(tid);
if (res != CELL_EBUSY) return res;
2014-01-19 22:19:37 +01:00
u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
do // waiting
{
if (Emu.IsStopped()) return CELL_ETIMEDOUT;
2014-01-19 22:19:37 +01:00
Sleep(1);
res = lwmutex->trylock(tid);
if (res != CELL_EBUSY) return res;
if (!lwmutex->attribute) return CELL_EINVAL;
2014-01-19 22:19:37 +01:00
if (counter++ > max_counter)
{
if (!timeout)
{
sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr());
counter = 0;
2014-01-19 22:19:37 +01:00
}
else
{
return CELL_ETIMEDOUT;
}
}
} while (true);
}
2014-01-19 22:19:37 +01:00
int sys_lwmutex_trylock(mem_ptr_t<sys_lwmutex_t> lwmutex)
{
sc_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
2014-01-19 22:19:37 +01:00
if (!lwmutex.IsGood()) return CELL_EFAULT;
if (!lwmutex->attribute) return CELL_EINVAL;
return lwmutex->trylock(GetCurrentPPUThread().GetId());
}
2014-01-19 22:19:37 +01:00
int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
{
sc_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
2014-01-19 22:19:37 +01:00
if (!lwmutex.IsGood()) return CELL_EFAULT;
if (!lwmutex->unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM;
return CELL_OK;
}