2014-01-29 21:31:09 +01:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2015-03-06 23:58:42 +01:00
|
|
|
#include "Emu/IdManager.h"
|
2014-01-29 21:31:09 +01:00
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
|
|
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2015-03-02 22:09:20 +01:00
|
|
|
#include "sleep_queue.h"
|
2014-12-23 00:31:11 +01:00
|
|
|
#include "sys_time.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_lwmutex.h"
|
|
|
|
|
#include "sys_lwcond.h"
|
2014-01-29 21:31:09 +01:00
|
|
|
|
|
|
|
|
SysCallBase sys_lwcond("sys_lwcond");
|
|
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2015-01-19 20:41:31 +01:00
|
|
|
const u32 addr = vm::get_addr(&lwmutex);
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<Lwcond> lw(new Lwcond(name_u64, addr));
|
2014-09-20 02:08:12 +02:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
const u32 id = Emu.GetIdManager().GetNewID(lw, TYPE_LWCOND);
|
2015-01-19 20:41:31 +01:00
|
|
|
|
2014-12-28 14:15:22 +01:00
|
|
|
lw->queue.set_full_name(fmt::Format("Lwcond(%d, addr=0x%x)", id, lw->addr));
|
2014-11-20 20:41:04 +01:00
|
|
|
lwcond.lwmutex.set(addr);
|
2014-09-19 02:19:22 +02:00
|
|
|
lwcond.lwcond_queue = id;
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), addr, id);
|
2014-01-29 21:31:09 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
|
|
|
|
|
{
|
|
|
|
|
sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)",
|
|
|
|
|
lwcond.addr(), lwmutex.addr(), attr.addr());
|
|
|
|
|
|
|
|
|
|
return lwcond_create(*lwcond, *lwmutex, attr->name_u64);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-02 03:05:13 +02:00
|
|
|
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.addr());
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-03-22 22:04:55 +01:00
|
|
|
u32 id = lwcond->lwcond_queue;
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Lwcond> lw;
|
2014-03-22 22:04:55 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(id, lw))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
if (lw->queue.count()) // TODO: safely make object unusable
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-03-22 22:04:55 +01:00
|
|
|
Emu.GetIdManager().RemoveID(id);
|
2014-01-29 21:31:09 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-02 03:05:13 +02:00
|
|
|
s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.addr());
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Lwcond> lw;
|
2014-03-22 22:04:55 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 17:30:35 +01:00
|
|
|
auto mutex = lwcond->lwmutex.to_le();
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (u32 target = lw->queue.signal(mutex->attribute))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-03-22 22:04:55 +01:00
|
|
|
if (Emu.IsStopped())
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_lwcond.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
2014-03-22 22:04:55 +01:00
|
|
|
return CELL_OK;
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-29 21:31:09 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-02 03:05:13 +02:00
|
|
|
s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.addr());
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Lwcond> lw;
|
2014-03-22 22:04:55 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 17:30:35 +01:00
|
|
|
auto mutex = lwcond->lwmutex.to_le();
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
while (u32 target = lw->queue.signal(mutex->attribute))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-03-22 22:04:55 +01:00
|
|
|
if (Emu.IsStopped())
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_lwcond.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
2014-03-22 22:04:55 +01:00
|
|
|
return CELL_OK;
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-29 21:31:09 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-02 03:05:13 +02:00
|
|
|
s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.addr(), ppu_thread_id);
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Lwcond> lw;
|
2014-03-22 22:04:55 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-26 11:35:30 +01:00
|
|
|
if (!Emu.GetIdManager().CheckID(ppu_thread_id))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (!lw->queue.signal_selected(ppu_thread_id))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EPERM;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 21:31:09 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
2014-01-29 21:31:09 +01:00
|
|
|
{
|
2014-09-02 03:05:13 +02:00
|
|
|
sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout);
|
2014-01-29 21:31:09 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
const u64 start_time = get_system_time();
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Lwcond> lw;
|
2014-03-22 22:04:55 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 17:30:35 +01:00
|
|
|
auto mutex = lwcond->lwmutex.to_le();
|
2014-12-23 00:31:11 +01:00
|
|
|
u32 tid_le = CPU.GetId();
|
2015-01-19 17:30:35 +01:00
|
|
|
auto tid = be_t<u32>::make(tid_le);
|
2014-01-31 00:40:05 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<sleep_queue_t> sq;
|
|
|
|
|
if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq))
|
2014-12-22 01:56:04 +01:00
|
|
|
{
|
|
|
|
|
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
|
|
|
|
|
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2014-03-22 22:04:55 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (mutex->owner.read_sync() != tid)
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
return CELL_EPERM;
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
lw->queue.push(tid_le, mutex->attribute);
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
auto old_recursive = mutex->recursive_count.read_relaxed();
|
|
|
|
|
mutex->recursive_count.exchange(be_t<u32>::make(0));
|
2014-03-22 22:04:55 +01:00
|
|
|
|
2015-01-19 17:30:35 +01:00
|
|
|
auto target = be_t<u32>::make(sq->signal(mutex->attribute));
|
2014-12-23 00:31:11 +01:00
|
|
|
if (!mutex->owner.compare_and_swap_test(tid, target))
|
2014-03-22 22:04:55 +01:00
|
|
|
{
|
2014-12-22 01:56:04 +01:00
|
|
|
assert(!"sys_lwcond_wait(): mutex unlocking failed");
|
2014-03-22 22:04:55 +01:00
|
|
|
}
|
2014-01-31 00:40:05 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
bool signaled = false;
|
2014-02-14 12:40:41 +01:00
|
|
|
while (true)
|
2014-01-31 00:40:05 +01:00
|
|
|
{
|
2015-01-02 13:32:54 +01:00
|
|
|
if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads
|
2014-01-31 00:40:05 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
s32 res = mutex->lock(tid, timeout ? get_system_time() - start_time : 0); // this is bad
|
2014-12-23 00:31:11 +01:00
|
|
|
if (res == CELL_OK)
|
2014-03-22 22:04:55 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
break;
|
2014-03-22 22:04:55 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
switch (res)
|
|
|
|
|
{
|
|
|
|
|
case static_cast<int>(CELL_EDEADLK):
|
|
|
|
|
{
|
|
|
|
|
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue);
|
|
|
|
|
return CELL_OK; // mutex not locked (but already locked in the incorrect way)
|
|
|
|
|
}
|
|
|
|
|
case static_cast<int>(CELL_ESRCH):
|
|
|
|
|
{
|
|
|
|
|
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
|
|
|
|
return CELL_ESRCH; // mutex not locked
|
|
|
|
|
}
|
|
|
|
|
case static_cast<int>(CELL_ETIMEDOUT):
|
|
|
|
|
{
|
|
|
|
|
return CELL_ETIMEDOUT; // mutex not locked
|
|
|
|
|
}
|
|
|
|
|
case static_cast<int>(CELL_EINVAL):
|
|
|
|
|
{
|
|
|
|
|
sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
|
|
|
|
return CELL_EINVAL; // mutex not locked
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res);
|
|
|
|
|
return CELL_EINVAL; // mutex not locked
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-01-31 00:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (timeout && get_system_time() - start_time > timeout)
|
2014-01-31 00:40:05 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
if (!lw->queue.invalidate(tid_le, mutex->attribute))
|
|
|
|
|
{
|
|
|
|
|
assert(!"sys_lwcond_wait() failed (timeout)");
|
|
|
|
|
}
|
2014-12-23 00:31:11 +01:00
|
|
|
return CELL_ETIMEDOUT; // mutex not locked
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
2014-12-23 00:31:11 +01:00
|
|
|
|
2014-02-14 12:40:41 +01:00
|
|
|
if (Emu.IsStopped())
|
|
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
|
|
|
|
return CELL_OK;
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-03-22 22:04:55 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
mutex->recursive_count.exchange(old_recursive);
|
2014-03-22 22:04:55 +01:00
|
|
|
return CELL_OK;
|
2014-01-29 21:31:09 +01:00
|
|
|
}
|