2013-06-30 10:46:29 +02:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2013-06-30 10:46:29 +02: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"
|
|
|
|
|
#include "sys_time.h"
|
2014-12-22 01:56:04 +01:00
|
|
|
#include "sys_mutex.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_cond.h"
|
2013-06-30 10:46:29 +02:00
|
|
|
|
|
|
|
|
SysCallBase sys_cond("sys_cond");
|
|
|
|
|
|
2014-10-11 19:20:01 +02:00
|
|
|
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute> attr)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-02-26 08:51:00 +01:00
|
|
|
sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)",
|
2014-09-02 03:05:13 +02:00
|
|
|
cond_id.addr(), mutex_id, attr.addr());
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-09-20 02:08:12 +02:00
|
|
|
LV2_LOCK(0);
|
|
|
|
|
|
2014-02-13 17:59:13 +01:00
|
|
|
if (attr->pshared.ToBE() != se32(0x200))
|
|
|
|
|
{
|
|
|
|
|
sys_cond.Error("Invalid pshared attribute(0x%x)", (u32)attr->pshared);
|
|
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Mutex> mutex;
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond(new Cond(mutex, attr->name_u64));
|
2014-12-23 00:31:11 +01:00
|
|
|
const u32 id = sys_cond.GetNewId(cond, TYPE_COND);
|
2014-09-01 02:51:48 +02:00
|
|
|
*cond_id = id;
|
2014-02-14 12:40:41 +01:00
|
|
|
mutex->cond_count++;
|
2014-09-01 02:51:48 +02:00
|
|
|
sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_cond_destroy(u32 cond_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-02-14 12:40:41 +01:00
|
|
|
sys_cond.Warning("sys_cond_destroy(cond_id=%d)", cond_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-09-20 02:08:12 +02:00
|
|
|
LV2_LOCK(0);
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond;
|
2014-02-13 17:59:13 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
if (cond->queue.count()) // TODO: safely make object unusable
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-02-14 12:40:41 +01:00
|
|
|
cond->mutex->cond_count--;
|
2013-06-30 10:46:29 +02:00
|
|
|
Emu.GetIdManager().RemoveID(cond_id);
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_cond_signal(u32 cond_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-02-26 11:35:30 +01:00
|
|
|
sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond;
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Mutex> mutex = cond->mutex;
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (u32 target = cond->queue.pop(mutex->protocol))
|
2014-02-03 14:12:25 +01:00
|
|
|
{
|
2014-12-24 23:24:17 +01:00
|
|
|
cond->signal.push(target);
|
2014-03-07 22:31:08 +01:00
|
|
|
|
2014-03-15 16:43:14 +01:00
|
|
|
if (Emu.IsStopped())
|
2014-02-03 14:12:25 +01:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_cond.Warning("sys_cond_signal(id=%d) aborted", cond_id);
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_cond_signal_all(u32 cond_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-02-26 11:35:30 +01:00
|
|
|
sys_cond.Log("sys_cond_signal_all(cond_id=%d)", cond_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond;
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Mutex> mutex = cond->mutex;
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
while (u32 target = cond->queue.pop(mutex->protocol))
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-12-24 23:24:17 +01:00
|
|
|
cond->signal.push(target);
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-03-07 22:31:08 +01:00
|
|
|
if (Emu.IsStopped())
|
|
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_cond.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
|
2014-06-21 16:26:37 +02:00
|
|
|
break;
|
2014-03-07 22:31:08 +01:00
|
|
|
}
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-02-26 11:35:30 +01:00
|
|
|
sys_cond.Log("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id);
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond;
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-02-26 11:35:30 +01:00
|
|
|
if (!Emu.GetIdManager().CheckID(thread_id))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (!cond->queue.invalidate(thread_id))
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EPERM;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Mutex> mutex = cond->mutex;
|
2014-02-26 11:35:30 +01:00
|
|
|
|
|
|
|
|
u32 target = thread_id;
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-12-24 23:24:17 +01:00
|
|
|
cond->signal.push(target);
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Emu.IsStopped())
|
|
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_cond.Warning("sys_cond_signal_to(id=%d, to=%d) aborted", cond_id, thread_id);
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-02-13 17:59:13 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
2014-02-26 11:35:30 +01:00
|
|
|
sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout);
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Cond> cond;
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Mutex> mutex = cond->mutex;
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
const u32 tid = CPU.GetId();
|
|
|
|
|
if (mutex->owner.read_sync() != tid)
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-02-26 11:35:30 +01:00
|
|
|
return CELL_EPERM;
|
2014-02-14 12:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
cond->queue.push(tid, mutex->protocol);
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
auto old_recursive = mutex->recursive_count.load();
|
|
|
|
|
mutex->recursive_count = 0;
|
2014-12-23 00:31:11 +01:00
|
|
|
if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol)))
|
|
|
|
|
{
|
|
|
|
|
assert(!"sys_cond_wait() failed");
|
|
|
|
|
}
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
bool pushed_in_sleep_queue = false;
|
|
|
|
|
const u64 time_start = get_system_time();
|
2014-02-26 11:35:30 +01:00
|
|
|
while (true)
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
u32 signaled;
|
2014-12-24 23:24:17 +01:00
|
|
|
if (cond->signal.try_peek(signaled) && signaled == tid) // check signaled threads
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
if (mutex->owner.compare_and_swap_test(0, tid)) // try to lock
|
2014-03-19 01:32:23 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pushed_in_sleep_queue)
|
|
|
|
|
{
|
|
|
|
|
mutex->queue.push(tid, mutex->protocol);
|
|
|
|
|
pushed_in_sleep_queue = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto old_owner = mutex->owner.compare_and_swap(0, tid);
|
|
|
|
|
if (!old_owner)
|
|
|
|
|
{
|
|
|
|
|
mutex->queue.invalidate(tid);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (old_owner == tid)
|
|
|
|
|
{
|
|
|
|
|
break;
|
2014-03-19 01:32:23 +01:00
|
|
|
}
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
2014-02-13 17:59:13 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
if (timeout && get_system_time() - time_start > timeout)
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
cond->queue.invalidate(tid);
|
|
|
|
|
CPU.owned_mutexes--; // ???
|
|
|
|
|
return CELL_ETIMEDOUT; // mutex not locked
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
2014-12-23 00:31:11 +01:00
|
|
|
|
2014-02-26 11:35:30 +01:00
|
|
|
if (Emu.IsStopped())
|
|
|
|
|
{
|
2014-12-23 00:31:11 +01:00
|
|
|
sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id);
|
|
|
|
|
return CELL_OK;
|
2014-02-26 11:35:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-03-19 01:32:23 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
mutex->recursive_count = old_recursive;
|
2014-12-24 23:24:17 +01:00
|
|
|
cond->signal.pop(cond_id /* unused result */);
|
2014-03-19 01:32:23 +01:00
|
|
|
return CELL_OK;
|
2014-06-17 17:44:03 +02:00
|
|
|
}
|