rpcsx/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp

235 lines
4.3 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
2015-03-06 23:58:42 +01:00
#include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
2014-08-23 16:51:51 +02:00
#include "Emu/Cell/PPUThread.h"
2014-12-22 01:56:04 +01:00
#include "sys_mutex.h"
#include "sys_cond.h"
SysCallBase sys_cond("sys_cond");
extern u64 get_system_time();
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
{
2015-04-14 04:00:31 +02:00
sys_cond.Warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, 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;
2015-07-12 13:52:55 +02:00
const auto mutex = Emu.GetIdManager().get<lv2_mutex_t>(mutex_id);
2015-03-06 23:10:04 +01:00
2015-04-12 03:36:25 +02:00
if (!mutex)
2014-02-13 17:59:13 +01:00
{
2015-03-06 23:10:04 +01:00
return CELL_ESRCH;
}
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key.data() || attr->flags.data())
2015-03-06 23:10:04 +01:00
{
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;
}
2015-03-06 23:10:04 +01:00
if (!++mutex->cond_count)
2014-02-13 17:59:13 +01:00
{
2015-07-01 19:09:26 +02:00
throw EXCEPTION("Unexpected cond_count");
2014-02-13 17:59:13 +01:00
}
*cond_id = Emu.GetIdManager().make<lv2_cond_t>(mutex, attr->name_u64);
return CELL_OK;
}
s32 sys_cond_destroy(u32 cond_id)
{
2015-04-14 04:00:31 +02:00
sys_cond.Warning("sys_cond_destroy(cond_id=0x%x)", cond_id);
2015-03-06 23:10:04 +01:00
LV2_LOCK;
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id);
2015-03-06 23:10:04 +01:00
2015-04-12 03:36:25 +02:00
if (!cond)
2014-02-13 17:59:13 +01:00
{
return CELL_ESRCH;
}
if (!cond->sq.empty())
2014-02-13 17:59:13 +01:00
{
return CELL_EBUSY;
}
2015-03-06 23:10:04 +01:00
if (!cond->mutex->cond_count--)
{
2015-07-01 19:09:26 +02:00
throw EXCEPTION("Unexpected cond_count");
2015-03-06 23:10:04 +01:00
}
Emu.GetIdManager().remove<lv2_cond_t>(cond_id);
2015-03-06 23:10:04 +01:00
return CELL_OK;
}
s32 sys_cond_signal(u32 cond_id)
{
2015-04-14 04:00:31 +02:00
sys_cond.Log("sys_cond_signal(cond_id=0x%x)", cond_id);
2015-03-06 23:10:04 +01:00
LV2_LOCK;
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id);
2015-03-06 23:10:04 +01:00
2015-04-12 03:36:25 +02:00
if (!cond)
{
return CELL_ESRCH;
}
for (auto& thread : cond->sq)
2015-03-06 23:10:04 +01:00
{
// signal one waiting thread; protocol is ignored in current implementation
if (thread->Signal())
{
return CELL_OK;
}
2015-03-06 23:10:04 +01:00
}
2014-02-26 11:35:30 +01:00
return CELL_OK;
}
s32 sys_cond_signal_all(u32 cond_id)
{
2015-04-14 04:00:31 +02:00
sys_cond.Log("sys_cond_signal_all(cond_id=0x%x)", cond_id);
2015-03-06 23:10:04 +01:00
LV2_LOCK;
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id);
2015-03-06 23:10:04 +01:00
2015-04-12 03:36:25 +02:00
if (!cond)
{
return CELL_ESRCH;
}
for (auto& thread : cond->sq)
{
// signal all waiting threads; protocol is ignored in current implementation
if (thread->Signal())
{
2015-07-08 17:01:59 +02:00
;
}
}
return CELL_OK;
}
s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
{
2015-04-14 04:00:31 +02:00
sys_cond.Log("sys_cond_signal_to(cond_id=0x%x, thread_id=0x%x)", cond_id, thread_id);
2015-03-06 23:10:04 +01:00
LV2_LOCK;
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id);
2015-04-12 03:36:25 +02:00
if (!cond)
{
return CELL_ESRCH;
}
// TODO: check if CELL_ESRCH is returned if thread_id is invalid
for (auto& thread : cond->sq)
2014-02-26 11:35:30 +01:00
{
// signal specified thread
if (thread->GetId() == thread_id && thread->Signal())
{
return CELL_OK;
}
2014-02-26 11:35:30 +01:00
}
2015-03-06 23:10:04 +01:00
return CELL_EPERM;
2014-02-13 17:59:13 +01:00
}
s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout)
2014-02-13 17:59:13 +01:00
{
2015-04-14 04:00:31 +02:00
sys_cond.Log("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout);
const u64 start_time = get_system_time();
2015-03-06 23:10:04 +01:00
LV2_LOCK;
const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id);
2015-03-06 23:10:04 +01:00
2015-04-12 03:36:25 +02:00
if (!cond)
{
return CELL_ESRCH;
}
// check current ownership
if (cond->mutex->owner.get() != &ppu)
{
2014-02-26 11:35:30 +01:00
return CELL_EPERM;
}
2015-07-17 18:27:12 +02:00
// save the recursive value
2015-03-06 23:10:04 +01:00
const u32 recursive_value = cond->mutex->recursive_count.exchange(0);
2014-02-13 17:59:13 +01:00
2015-07-17 18:27:12 +02:00
// unlock the mutex
cond->mutex->unlock(lv2_lock);
2015-04-12 03:36:25 +02:00
{
// add waiter; protocol is ignored in current implementation
sleep_queue_entry_t waiter(ppu, cond->sq);
while (!ppu.Signaled())
{
if (timeout)
2015-04-12 03:36:25 +02:00
{
const u64 passed = get_system_time() - start_time;
if (passed >= timeout || ppu.cv.wait_for(lv2_lock, std::chrono::microseconds(timeout - passed)) == std::cv_status::timeout)
{
break;
}
}
else
{
ppu.cv.wait(lv2_lock);
2015-04-12 03:36:25 +02:00
}
2015-03-10 15:42:08 +01:00
CHECK_EMU_STATUS;
2014-02-26 11:35:30 +01:00
}
}
// reown the mutex (could be set when notified)
if (!cond->mutex->owner)
{
2015-07-12 13:52:55 +02:00
cond->mutex->owner = ppu.shared_from_this();
}
2015-03-06 23:10:04 +01:00
if (cond->mutex->owner.get() != &ppu)
{
// add waiter; protocol is ignored in current implementation
sleep_queue_entry_t waiter(ppu, cond->mutex->sq);
while (!ppu.Signaled())
{
ppu.cv.wait(lv2_lock);
CHECK_EMU_STATUS;
}
if (cond->mutex->owner.get() != &ppu)
{
throw EXCEPTION("Unexpected mutex owner");
}
}
// restore the recursive value
2015-03-06 23:10:04 +01:00
cond->mutex->recursive_count = recursive_value;
// check timeout
if (timeout && get_system_time() - start_time > timeout)
{
return CELL_ETIMEDOUT;
}
2015-03-06 23:10:04 +01:00
2014-03-19 01:32:23 +01:00
return CELL_OK;
}