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-07-11 13:59:13 +02:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2015-03-02 22:09:20 +01:00
|
|
|
#include "sleep_queue.h"
|
2014-07-06 01:30:28 +02:00
|
|
|
#include "sys_time.h"
|
2014-09-19 02:19:22 +02:00
|
|
|
#include "sys_semaphore.h"
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-08-23 16:51:51 +02:00
|
|
|
SysCallBase sys_semaphore("sys_semaphore");
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64)
|
|
|
|
|
{
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Semaphore> sem(new Semaphore(initial_count, max_count, protocol, name_u64));
|
2014-12-28 14:15:22 +01:00
|
|
|
|
2015-03-06 23:10:04 +01:00
|
|
|
const u32 id = Emu.GetIdManager().GetNewID(sem, TYPE_SEMAPHORE);
|
2014-12-28 14:15:22 +01:00
|
|
|
sem->queue.set_full_name(fmt::Format("Semaphore(%d)", id));
|
|
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol, id);
|
2014-09-19 02:19:22 +02:00
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-11 19:20:01 +02:00
|
|
|
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute> attr, s32 initial_count, s32 max_count)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
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);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-28 14:15:22 +01:00
|
|
|
if (!sem)
|
|
|
|
|
{
|
|
|
|
|
sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr());
|
|
|
|
|
return CELL_EFAULT;
|
|
|
|
|
}
|
2014-11-12 23:25:27 +01:00
|
|
|
|
2014-12-28 14:15:22 +01:00
|
|
|
if (!attr)
|
|
|
|
|
{
|
|
|
|
|
sys_semaphore.Error("sys_semaphore_create(): An invalid argument value is specified (attr_addr=0x%x)", attr.addr());
|
|
|
|
|
return CELL_EFAULT;
|
|
|
|
|
}
|
2014-11-12 23:25:27 +01:00
|
|
|
|
2014-06-22 12:59:28 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-13 15:54:36 +01:00
|
|
|
switch (attr->protocol.data())
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
case se32(SYS_SYNC_FIFO): break;
|
|
|
|
|
case se32(SYS_SYNC_PRIORITY): break;
|
2015-03-08 03:32:41 +01:00
|
|
|
case se32(SYS_SYNC_PRIORITY_INHERIT): break;
|
2015-01-13 15:54:36 +01:00
|
|
|
default: sys_semaphore.Error("Unknown protocol attribute (0x%x)", attr->protocol); return CELL_EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attr->pshared.data() != se32(0x200))
|
|
|
|
|
{
|
|
|
|
|
sys_semaphore.Error("Unknown pshared attribute (0x%x)", attr->pshared);
|
|
|
|
|
return CELL_EINVAL;
|
2014-06-21 16:24:27 +02:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
*sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64);
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_semaphore_destroy(u32 sem_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_semaphore.Warning("sys_semaphore_destroy(sem_id=%d)", sem_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Semaphore> sem;
|
2014-06-21 16:24:27 +02:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-24 17:09:32 +01:00
|
|
|
if (sem->queue.count()) // TODO: safely make object unusable
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-06-21 16:24:27 +02:00
|
|
|
Emu.GetIdManager().RemoveID(sem_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_wait(sem_id=%d, timeout=%lld)", sem_id, timeout);
|
2013-06-30 10:46:29 +02: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<Semaphore> sem;
|
2014-06-21 16:24:27 +02:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-06-21 16:24:27 +02:00
|
|
|
const u32 tid = GetCurrentPPUThread().GetId();
|
2015-01-02 00:41:29 +01:00
|
|
|
s32 old_value;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
sem->value.atomic_op_sync([&old_value](s32& value)
|
|
|
|
|
{
|
|
|
|
|
old_value = value;
|
|
|
|
|
if (value > 0)
|
|
|
|
|
{
|
|
|
|
|
value--;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (old_value > 0)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
|
2014-12-23 00:31:11 +01:00
|
|
|
sem->queue.push(tid, sem->protocol);
|
2014-06-21 16:24:27 +02:00
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
|
2014-06-21 16:24:27 +02:00
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
if (sem->queue.pop(tid, sem->protocol))
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
break;
|
2014-06-21 16:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
assert(!sem->value.read_sync());
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
|
|
|
|
|
2014-06-21 16:24:27 +02:00
|
|
|
if (timeout && get_system_time() - start_time > timeout)
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
if (!sem->queue.invalidate(tid, sem->protocol))
|
|
|
|
|
{
|
2015-01-02 17:02:31 +01:00
|
|
|
if (sem->queue.pop(tid, sem->protocol))
|
|
|
|
|
{
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
assert(!"sys_semaphore_wait() failed (timeout)");
|
|
|
|
|
}
|
2014-06-21 16:24:27 +02:00
|
|
|
return CELL_ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (Emu.IsStopped())
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem_id);
|
2014-06-21 16:24:27 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:38:34 +02:00
|
|
|
s32 sys_semaphore_trywait(u32 sem_id)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_trywait(sem_id=%d)", sem_id);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Semaphore> sem;
|
2014-06-21 16:24:27 +02:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
s32 old_value;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
sem->value.atomic_op_sync([&old_value](s32& value)
|
|
|
|
|
{
|
|
|
|
|
old_value = value;
|
|
|
|
|
if (value > 0)
|
|
|
|
|
{
|
|
|
|
|
value--;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (old_value > 0)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-19 02:19:22 +02:00
|
|
|
s32 sys_semaphore_post(u32 sem_id, s32 count)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Semaphore> sem;
|
2014-06-21 16:24:27 +02:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count < 0)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (count + sem->value.read_sync() - (s32)sem->queue.count() > sem->max)
|
2013-11-26 01:23:25 +01:00
|
|
|
{
|
2014-06-22 12:59:28 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (u32 target = sem->queue.signal(sem->protocol))
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
sem->value.atomic_op([count](s32& value)
|
|
|
|
|
{
|
|
|
|
|
value += count;
|
|
|
|
|
});
|
2014-06-21 16:24:27 +02:00
|
|
|
count = 0;
|
|
|
|
|
}
|
2013-11-26 01:23:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-11 19:20:01 +02:00
|
|
|
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count)
|
2013-11-26 01:23:25 +01:00
|
|
|
{
|
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());
|
2013-11-26 01:23:25 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
if (!count)
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (addr=0x%x)", count.addr());
|
2014-12-24 00:38:13 +01:00
|
|
|
return CELL_EFAULT;
|
|
|
|
|
}
|
2014-11-12 23:25:27 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
std::shared_ptr<Semaphore> sem;
|
2014-06-21 16:24:27 +02:00
|
|
|
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-11-26 01:23:25 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
*count = sem->value.read_sync();
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|