2012-11-15 00:39:56 +01:00
|
|
|
#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>
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
SysCallBase sc_lwmutex("sys_lwmutex");
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
std::mutex g_lwmutex;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
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)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
sc_lwmutex.Log("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)",
|
|
|
|
|
lwmutex.GetAddr(), attr.GetAddr());
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
switch ((u32)attr->attr_recursive)
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
case SYS_SYNC_RECURSIVE: break;
|
|
|
|
|
case SYS_SYNC_NOT_RECURSIVE: break;
|
|
|
|
|
default: return CELL_EINVAL;
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
switch ((u32)attr->attr_protocol)
|
|
|
|
|
{
|
|
|
|
|
case SYS_SYNC_PRIORITY: break;
|
|
|
|
|
case SYS_SYNC_RETRY: sc_lwmutex.Error("TODO: SYS_SYNC_RETRY attr"); break;
|
|
|
|
|
case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Error("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
|
|
|
|
|
case SYS_SYNC_FIFO: sc_lwmutex.Error("TODO: SYS_SYNC_FIFO attr"); break;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
sc_lwmutex.Log("*** lwmutex created [%s] (protocol=0x%x, recursive=0x%x)",
|
|
|
|
|
attr->name, (u32)attr->attr_protocol, (u32)attr->attr_recursive);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
2013-06-30 10:46:29 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
sc_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout);
|
|
|
|
|
|
|
|
|
|
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
PPCThread& thr = GetCurrentPPUThread();
|
2014-01-19 22:19:37 +01:00
|
|
|
const u32 id = thr.GetId();
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
{ // global lock
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_lwmutex);
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
if ((u32)lwmutex->attribute & SYS_SYNC_RECURSIVE)
|
|
|
|
|
{
|
|
|
|
|
if (id == (u32)lwmutex->owner)
|
|
|
|
|
{
|
|
|
|
|
lwmutex->recursive_count = lwmutex->recursive_count + 1;
|
|
|
|
|
if (lwmutex->recursive_count == 0xffffffff) return CELL_EKRESOURCE;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // recursive not allowed
|
|
|
|
|
{
|
|
|
|
|
if (id == (u32)lwmutex->owner)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EDEADLK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!lwmutex->owner) // lock
|
|
|
|
|
{
|
|
|
|
|
lwmutex->owner = id;
|
|
|
|
|
lwmutex->recursive_count = 1;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
lwmutex->waiter = id; // not used yet
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
2014-01-19 22:19:37 +01:00
|
|
|
|
|
|
|
|
u32 counter = 0;
|
|
|
|
|
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
|
|
|
|
do // waiting
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
Sleep(1);
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
{ // global lock
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_lwmutex);
|
|
|
|
|
|
|
|
|
|
if (!lwmutex->owner) // lock
|
|
|
|
|
{
|
|
|
|
|
lwmutex->owner = id;
|
|
|
|
|
lwmutex->recursive_count = 1;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
lwmutex->waiter = id; // not used yet
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (counter++ > max_counter)
|
|
|
|
|
{
|
|
|
|
|
if (!timeout)
|
|
|
|
|
{ // endless waiter
|
|
|
|
|
sc_lwmutex.Error("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr());
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return CELL_ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (true);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
int sys_lwmutex_trylock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
sc_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
|
|
|
|
|
|
|
|
|
PPCThread& thr = GetCurrentPPUThread();
|
|
|
|
|
const u32 id = thr.GetId();
|
|
|
|
|
|
|
|
|
|
{ // global lock
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_lwmutex);
|
|
|
|
|
|
|
|
|
|
if ((u32)lwmutex->attribute & SYS_SYNC_RECURSIVE)
|
|
|
|
|
{
|
|
|
|
|
if (id == (u32)lwmutex->owner)
|
|
|
|
|
{
|
|
|
|
|
lwmutex->recursive_count = lwmutex->recursive_count + 1;
|
|
|
|
|
if (lwmutex->recursive_count == 0xffffffff) return CELL_EKRESOURCE;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // recursive not allowed
|
|
|
|
|
{
|
|
|
|
|
if (id == (u32)lwmutex->owner)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EDEADLK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!lwmutex->owner) // try lock
|
|
|
|
|
{
|
|
|
|
|
lwmutex->owner = id;
|
|
|
|
|
lwmutex->recursive_count = 1;
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
sc_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
|
|
|
|
|
|
|
|
|
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
PPCThread& thr = GetCurrentPPUThread();
|
|
|
|
|
const u32 id = thr.GetId();
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
{ // global lock
|
|
|
|
|
std::lock_guard<std::mutex> lock(g_lwmutex);
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-01-19 22:19:37 +01:00
|
|
|
if (id != (u32)lwmutex->owner)
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
return CELL_EPERM;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lwmutex->recursive_count = (u32)lwmutex->recursive_count - 1;
|
|
|
|
|
if (!lwmutex->recursive_count)
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-01-19 22:19:37 +01:00
|
|
|
lwmutex->waiter = 0; // not used yet
|
|
|
|
|
lwmutex->owner = 0; // release
|
|
|
|
|
/* CPUThread* thr = Emu.GetCPU().GetThread(lwmutex->owner);
|
|
|
|
|
if(thr)
|
|
|
|
|
{
|
|
|
|
|
thr->Wait(false);
|
|
|
|
|
} */
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
2014-01-19 22:19:37 +01:00
|
|
|
return CELL_OK;
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|