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

215 lines
4.6 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#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-07-11 13:59:13 +02:00
#include "Emu/Cell/PPUThread.h"
#include "sys_semaphore.h"
#include "sys_time.h"
2014-08-23 16:51:51 +02:00
//#include "Utilities/SMutex.h"
2014-08-23 16:51:51 +02:00
SysCallBase sys_semaphore("sys_semaphore");
2014-09-02 03:05:13 +02:00
s32 sys_semaphore_create(vm::ptr<be_t<u32>> sem, vm::ptr<sys_semaphore_attribute> attr, int initial_count, int max_count)
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)",
2014-09-02 03:05:13 +02:00
sem.addr(), attr.addr(), initial_count, max_count);
if (max_count <= 0 || initial_count > max_count || initial_count < 0)
2014-06-21 16:24:27 +02:00
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count);
2014-06-21 16:24:27 +02:00
return CELL_EINVAL;
}
2014-06-21 16:24:27 +02:00
if (attr->pshared.ToBE() != se32(0x200))
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Error("sys_semaphore_create(): invalid pshared value(0x%x)", (u32)attr->pshared);
2014-06-21 16:24:27 +02:00
return CELL_EINVAL;
}
switch (attr->protocol.ToBE())
{
case se32(SYS_SYNC_FIFO): break;
case se32(SYS_SYNC_PRIORITY): break;
2014-08-23 16:51:51 +02:00
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_semaphore.Todo("SYS_SYNC_PRIORITY_INHERIT"); break;
case se32(SYS_SYNC_RETRY): sys_semaphore.Error("SYS_SYNC_RETRY"); return CELL_EINVAL;
default: sys_semaphore.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL;
2014-06-21 16:24:27 +02:00
}
2014-09-01 02:51:48 +02:00
u32 id = sys_semaphore.GetNewId(new Semaphore(initial_count, max_count, attr->protocol, attr->name_u64), TYPE_SEMAPHORE);
2014-09-02 00:22:13 +02:00
*sem = id;
2014-08-23 16:51:51 +02:00
sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d",
2014-09-01 02:51:48 +02:00
std::string(attr->name, 8).c_str(), (u32)attr->protocol, id);
2014-09-13 22:40:12 +02:00
Emu.GetSyncPrimManager().AddSemaphoreData(id, std::string(attr->name, 8), initial_count, max_count);
return CELL_OK;
}
s32 sys_semaphore_destroy(u32 sem_id)
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Warning("sys_semaphore_destroy(sem_id=%d)", sem_id);
2014-06-21 16:24:27 +02:00
Semaphore* sem;
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
{
return CELL_ESRCH;
}
if (!sem->m_queue.finalize())
{
return CELL_EBUSY;
}
2014-06-21 16:24:27 +02:00
Emu.GetIdManager().RemoveID(sem_id);
2014-09-13 22:40:12 +02:00
Emu.GetSyncPrimManager().EraseSemaphoreData(sem_id);
return CELL_OK;
}
s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Log("sys_semaphore_wait(sem_id=%d, timeout=%lld)", sem_id, timeout);
2014-06-21 16:24:27 +02:00
Semaphore* sem;
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
{
return CELL_ESRCH;
}
2014-06-21 16:24:27 +02:00
const u32 tid = GetCurrentPPUThread().GetId();
const u64 start_time = get_system_time();
2014-06-21 16:24:27 +02:00
{
std::lock_guard<std::mutex> lock(sem->m_mutex);
if (sem->m_value > 0)
{
sem->m_value--;
return CELL_OK;
}
sem->m_queue.push(tid);
}
while (true)
{
if (Emu.IsStopped())
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem_id);
2014-06-21 16:24:27 +02:00
return CELL_OK;
}
if (timeout && get_system_time() - start_time > timeout)
{
sem->m_queue.invalidate(tid);
2014-06-21 16:24:27 +02:00
return CELL_ETIMEDOUT;
}
if (tid == sem->signal)
{
std::lock_guard<std::mutex> lock(sem->m_mutex);
if (tid != sem->signal)
{
continue;
}
2014-06-21 16:24:27 +02:00
sem->signal = 0;
// TODO: notify signaler
return CELL_OK;
}
SM_Sleep();
}
}
s32 sys_semaphore_trywait(u32 sem_id)
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Log("sys_semaphore_trywait(sem_id=%d)", sem_id);
2014-06-21 16:24:27 +02:00
Semaphore* sem;
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
{
return CELL_ESRCH;
}
2014-06-21 16:24:27 +02:00
std::lock_guard<std::mutex> lock(sem->m_mutex);
2014-06-21 16:24:27 +02:00
if (sem->m_value > 0)
{
sem->m_value--;
return CELL_OK;
}
else
{
return CELL_EBUSY;
}
}
s32 sys_semaphore_post(u32 sem_id, int count)
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count);
2014-06-21 16:24:27 +02:00
Semaphore* sem;
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
{
return CELL_ESRCH;
}
if (count < 0)
{
return CELL_EINVAL;
}
if (count + sem->m_value - (int)sem->m_queue.count() > sem->max)
{
return CELL_EBUSY;
2014-06-21 16:24:27 +02:00
}
while (count > 0)
{
if (Emu.IsStopped())
{
2014-08-23 16:51:51 +02:00
sys_semaphore.Warning("sys_semaphore_post(%d) aborted", sem_id);
2014-06-21 16:24:27 +02:00
return CELL_OK;
}
std::lock_guard<std::mutex> lock(sem->m_mutex);
if (sem->signal && sem->m_queue.count())
{
SM_Sleep();
continue;
}
if (u32 target = (sem->protocol == SYS_SYNC_FIFO) ? sem->m_queue.pop() : sem->m_queue.pop_prio())
{
count--;
sem->signal = target;
Emu.GetCPU().NotifyThread(target);
}
else
{
sem->m_value += count;
count = 0;
}
}
return CELL_OK;
}
2014-09-01 02:51:48 +02:00
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<be_t<s32>> count)
{
2014-09-01 02:51:48 +02:00
sys_semaphore.Log("sys_semaphore_get_value(sem_id=%d, count_addr=0x%x)", sem_id, count.addr());
2014-06-21 16:24:27 +02:00
Semaphore* sem;
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
{
return CELL_ESRCH;
}
2014-06-21 16:24:27 +02:00
std::lock_guard<std::mutex> lock(sem->m_mutex);
2014-09-01 02:51:48 +02:00
*count = sem->m_value;
return CELL_OK;
}