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"
|
2015-03-06 23:58:42 +01:00
|
|
|
#include "Emu/IdManager.h"
|
2013-06-30 10:46:29 +02:00
|
|
|
#include "Emu/SysCalls/SysCalls.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"
|
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-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");
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
sys_cond.Warning("sys_cond_create(cond_id=*0x%x, mutex_id=%d, attr=*0x%x)", cond_id, mutex_id, attr);
|
2014-09-20 02:08:12 +02:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<mutex_t> mutex;
|
|
|
|
|
|
|
|
|
|
if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data())
|
|
|
|
|
{
|
|
|
|
|
sys_cond.Error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
2014-02-13 17:59:13 +01:00
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (!++mutex->cond_count)
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
throw __FUNCTION__;
|
2014-02-13 17:59:13 +01:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
std::shared_ptr<cond_t> cond(new cond_t(mutex, attr->name_u64));
|
2014-12-28 14:15:22 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
*cond_id = Emu.GetIdManager().GetNewID(cond, TYPE_COND);
|
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
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<cond_t> cond;
|
|
|
|
|
|
2014-02-13 17:59:13 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (cond->waiters || cond->signaled)
|
2014-02-13 17:59:13 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (!cond->mutex->cond_count--)
|
|
|
|
|
{
|
|
|
|
|
throw __FUNCTION__;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
Emu.GetIdManager().RemoveID(cond_id);
|
2015-03-06 23:10:04 +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(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
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<cond_t> cond;
|
|
|
|
|
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (cond->waiters)
|
|
|
|
|
{
|
|
|
|
|
cond->signaled++;
|
|
|
|
|
cond->waiters--;
|
|
|
|
|
cond->mutex->cv.notify_one();
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<cond_t> 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
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (cond->waiters)
|
2014-02-14 12:40:41 +01:00
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
cond->signaled += cond->waiters.exchange(0);
|
|
|
|
|
cond->mutex->cv.notify_all();
|
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
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
sys_cond.Todo("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id);
|
|
|
|
|
|
|
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<cond_t> 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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (!cond->waiters)
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EPERM;
|
|
|
|
|
}
|
2015-03-06 23:10:04 +01:00
|
|
|
|
|
|
|
|
cond->signaled++;
|
|
|
|
|
cond->waiters--;
|
|
|
|
|
cond->mutex->cv.notify_one();
|
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
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
const u64 start_time = get_system_time();
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<cond_t> cond;
|
|
|
|
|
|
2014-02-14 12:40:41 +01:00
|
|
|
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
std::shared_ptr<CPUThread> thread = Emu.GetCPU().GetThread(CPU.GetId());
|
2014-02-14 12:40:41 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
if (cond->mutex->owner.owner_before(thread) || thread.owner_before(cond->mutex->owner)) // check equality
|
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
|
|
|
}
|
|
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
// protocol is ignored in current implementation
|
|
|
|
|
cond->waiters++; assert(cond->waiters > 0);
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
// unlock mutex
|
|
|
|
|
cond->mutex->owner.reset();
|
2014-02-26 11:35:30 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
// not sure whether the recursive value is precisely saved
|
|
|
|
|
const u32 recursive_value = cond->mutex->recursive_count.exchange(0);
|
2014-02-13 17:59:13 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
while (!cond->mutex->owner.expired() || !cond->signaled)
|
|
|
|
|
{
|
|
|
|
|
if (!cond->signaled && timeout && get_system_time() - start_time > timeout)
|
2014-02-26 11:35:30 +01:00
|
|
|
{
|
2015-03-06 23:10:04 +01:00
|
|
|
// TODO: mutex not locked, timeout is possible only when signaled == 0
|
|
|
|
|
cond->waiters--; assert(cond->waiters >= 0);
|
|
|
|
|
return CELL_ETIMEDOUT;
|
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
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
cond->mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
2015-01-02 00:41:29 +01:00
|
|
|
}
|
2015-03-06 23:10:04 +01:00
|
|
|
|
|
|
|
|
// restore mutex owner
|
|
|
|
|
cond->mutex->owner = thread;
|
|
|
|
|
cond->mutex->recursive_count = recursive_value;
|
|
|
|
|
|
|
|
|
|
cond->signaled--; assert(cond->signaled >= 0);
|
|
|
|
|
|
2014-03-19 01:32:23 +01:00
|
|
|
return CELL_OK;
|
2014-06-17 17:44:03 +02:00
|
|
|
}
|