2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
2014-12-22 01:56:04 +01:00
|
|
|
#include "Emu/Memory/atomic_type.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
|
2014-08-26 01:55:37 +02:00
|
|
|
#include "Emu/CPU/CPUThreadManager.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2014-12-23 00:31:11 +01:00
|
|
|
#include "sleep_queue_type.h"
|
2014-12-22 01:56:04 +01:00
|
|
|
#include "sys_time.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_lwmutex.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-08-23 16:51:51 +02:00
|
|
|
SysCallBase sys_lwmutex("sys_lwmutex");
|
|
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64)
|
|
|
|
|
{
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<sleep_queue_t> sq(new sleep_queue_t(name_u64));
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
lwmutex.owner.write_relaxed(be_t<u32>::make(0));
|
2014-12-22 01:56:04 +01:00
|
|
|
lwmutex.waiter.write_relaxed(be_t<u32>::make(~0));
|
2014-09-19 02:19:22 +02:00
|
|
|
lwmutex.attribute = protocol | recursive;
|
2014-12-24 00:38:13 +01:00
|
|
|
lwmutex.recursive_count.write_relaxed(be_t<u32>::make(0));
|
|
|
|
|
u32 sq_id = sys_lwmutex.GetNewId(sq, TYPE_LWMUTEX);
|
2014-09-19 02:19:22 +02:00
|
|
|
lwmutex.sleep_queue = sq_id;
|
2015-01-19 20:41:31 +01:00
|
|
|
sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, vm::get_addr(&lwmutex)));
|
2014-09-19 02:19:22 +02:00
|
|
|
|
2015-01-12 19:12:06 +01:00
|
|
|
// 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);
|
2014-09-19 02:19:22 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-09-19 02:19:22 +02:00
|
|
|
sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr());
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-01-13 15:54:36 +01:00
|
|
|
switch (attr->recursive.data())
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-06-07 09:08:16 +02:00
|
|
|
case se32(SYS_SYNC_RECURSIVE): break;
|
|
|
|
|
case se32(SYS_SYNC_NOT_RECURSIVE): break;
|
2015-01-13 15:54:36 +01:00
|
|
|
default: sys_lwmutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL;
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-13 15:54:36 +01:00
|
|
|
switch (attr->protocol.data())
|
2014-01-19 22:19:37 +01:00
|
|
|
{
|
2014-06-07 09:08:16 +02:00
|
|
|
case se32(SYS_SYNC_PRIORITY): break;
|
|
|
|
|
case se32(SYS_SYNC_RETRY): break;
|
2015-01-13 15:54:36 +01:00
|
|
|
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL;
|
2014-06-07 09:08:16 +02:00
|
|
|
case se32(SYS_SYNC_FIFO): break;
|
2015-01-13 15:54:36 +01:00
|
|
|
default: sys_lwmutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL;
|
2014-01-19 22:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr());
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-09-20 02:08:12 +02:00
|
|
|
LV2_LOCK(0);
|
|
|
|
|
|
2014-02-09 12:11:48 +01:00
|
|
|
u32 sq_id = lwmutex->sleep_queue;
|
|
|
|
|
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
|
|
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
if (s32 res = lwmutex->trylock(be_t<u32>::make(~0)))
|
2014-02-06 23:55:48 +01:00
|
|
|
{
|
2014-12-24 17:09:32 +01:00
|
|
|
return res;
|
2014-02-06 23:55:48 +01:00
|
|
|
}
|
2014-12-24 17:09:32 +01:00
|
|
|
|
|
|
|
|
// 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;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout);
|
2014-01-19 22:19:37 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
return lwmutex->lock(be_t<u32>::make(CPU.GetId()), timeout);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr());
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
return lwmutex->trylock(be_t<u32>::make(CPU.GetId()));
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr());
|
2014-01-19 22:19:37 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
return lwmutex->unlock(be_t<u32>::make(CPU.GetId()));
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-22 01:56:04 +01:00
|
|
|
s32 sys_lwmutex_t::trylock(be_t<u32> tid)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2015-01-13 15:54:36 +01:00
|
|
|
if (attribute.data() == se32(0xDEADBEEF))
|
|
|
|
|
{
|
|
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
2014-03-06 12:40:50 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
if (!Emu.GetIdManager().CheckID(sleep_queue))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
const be_t<u32> old_owner = owner.read_sync();
|
2014-02-12 20:03:14 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (old_owner == tid)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2015-01-13 15:54:36 +01:00
|
|
|
if (attribute.data() & se32(SYS_SYNC_RECURSIVE))
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-24 00:38:13 +01:00
|
|
|
auto rv = recursive_count.read_relaxed();
|
2015-01-13 15:54:36 +01:00
|
|
|
if (!~(rv++).data())
|
2014-12-23 00:31:11 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EKRESOURCE;
|
|
|
|
|
}
|
2014-12-24 00:38:13 +01:00
|
|
|
|
|
|
|
|
recursive_count.exchange(rv);
|
2014-02-12 20:03:14 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return CELL_EDEADLK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (!owner.compare_and_swap_test(be_t<u32>::make(0), tid))
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-22 01:56:04 +01:00
|
|
|
return CELL_EBUSY;
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
2014-12-22 01:56:04 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
recursive_count.exchange(be_t<u32>::make(1));
|
2014-12-22 01:56:04 +01:00
|
|
|
return CELL_OK;
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-22 01:56:04 +01:00
|
|
|
s32 sys_lwmutex_t::unlock(be_t<u32> tid)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
if (owner.read_sync() != tid)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EPERM;
|
|
|
|
|
}
|
2014-12-23 00:31:11 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
auto rv = recursive_count.read_relaxed();
|
2015-01-13 15:54:36 +01:00
|
|
|
if (!rv.data() || (rv.data() != se32(1) && (attribute.data() & se32(SYS_SYNC_NOT_RECURSIVE))))
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-24 00:38:13 +01:00
|
|
|
sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv);
|
|
|
|
|
rv = 1;
|
2014-12-23 00:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
rv--;
|
|
|
|
|
recursive_count.exchange(rv);
|
2015-01-13 15:54:36 +01:00
|
|
|
if (!rv.data())
|
2014-12-23 00:31:11 +01:00
|
|
|
{
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<sleep_queue_t> sq;
|
2014-12-23 00:31:11 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
|
2014-03-07 13:03:42 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
return CELL_ESRCH;
|
2014-03-07 13:03:42 +01:00
|
|
|
}
|
2014-12-22 01:56:04 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (!owner.compare_and_swap_test(tid, be_t<u32>::make(sq->signal(attribute))))
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
assert(!"sys_lwmutex_t::unlock() failed");
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-12-23 00:31:11 +01:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-22 01:56:04 +01:00
|
|
|
s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
const u64 start_time = get_system_time();
|
|
|
|
|
|
2014-12-22 01:56:04 +01:00
|
|
|
switch (s32 res = trylock(tid))
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-22 01:56:04 +01:00
|
|
|
case static_cast<s32>(CELL_EBUSY): break;
|
2014-02-12 20:03:14 +01:00
|
|
|
default: return res;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<sleep_queue_t> sq;
|
2014-12-22 01:56:04 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2014-02-12 20:03:14 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
sq->push(tid, attribute);
|
2014-02-12 20:03:14 +01:00
|
|
|
|
2014-12-22 01:56:04 +01:00
|
|
|
while (true)
|
2014-02-12 20:03:14 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
auto old_owner = owner.compare_and_swap(be_t<u32>::make(0), tid);
|
2015-01-13 15:54:36 +01:00
|
|
|
if (!old_owner.data() || old_owner == tid)
|
2014-12-22 01:56:04 +01:00
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (timeout && get_system_time() - start_time > timeout)
|
2014-12-22 01:56:04 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
if (!sq->invalidate(tid, attribute))
|
|
|
|
|
{
|
|
|
|
|
assert(!"sys_lwmutex_t::lock() failed (timeout)");
|
|
|
|
|
}
|
2014-12-22 01:56:04 +01:00
|
|
|
return CELL_ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Emu.IsStopped())
|
|
|
|
|
{
|
|
|
|
|
sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue);
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
2014-02-12 20:03:14 +01:00
|
|
|
}
|
2014-12-22 01:56:04 +01:00
|
|
|
|
2015-01-02 17:02:31 +01:00
|
|
|
if (!sq->invalidate(tid, attribute) && !sq->pop(tid, attribute))
|
2015-01-02 00:41:29 +01:00
|
|
|
{
|
|
|
|
|
assert(!"sys_lwmutex_t::lock() failed (locking)");
|
|
|
|
|
}
|
2014-12-24 00:38:13 +01:00
|
|
|
recursive_count.exchange(be_t<u32>::make(1));
|
2014-12-22 01:56:04 +01:00
|
|
|
return CELL_OK;
|
2014-02-23 17:52:52 +01:00
|
|
|
}
|