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
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-03-08 04:37:07 +01:00
|
|
|
sys_semaphore.Warning("sys_semaphore_create(sem=*0x%x, attr=*0x%x, initial_val=%d, max_val=%d)", sem, attr, initial_val, max_val);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
if (!sem || !attr)
|
2014-12-28 14:15:22 +01:00
|
|
|
{
|
|
|
|
|
return CELL_EFAULT;
|
|
|
|
|
}
|
2014-11-12 23:25:27 +01:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
if (max_val <= 0 || initial_val > max_val || initial_val < 0)
|
2014-12-28 14:15:22 +01:00
|
|
|
{
|
2015-03-08 04:37:07 +01:00
|
|
|
sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_val=%d, max_val=%d)", initial_val, max_val);
|
2014-06-21 16:24:27 +02:00
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
const u32 protocol = attr->protocol;
|
|
|
|
|
|
|
|
|
|
switch (protocol)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
2015-03-08 04:37:07 +01:00
|
|
|
case SYS_SYNC_FIFO: break;
|
|
|
|
|
case SYS_SYNC_PRIORITY: break;
|
|
|
|
|
case SYS_SYNC_PRIORITY_INHERIT: break;
|
|
|
|
|
default: sys_semaphore.Error("sys_semaphore_create(): unknown protocol (0x%x)", protocol); return CELL_EINVAL;
|
2015-01-13 15:54:36 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data())
|
2015-01-13 15:54:36 +01:00
|
|
|
{
|
2015-03-08 04:37:07 +01:00
|
|
|
sys_semaphore.Error("sys_semaphore_create(): unknown attributes (pshared=0x%x, ipc_key=0x%x, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
2015-01-13 15:54:36 +01:00
|
|
|
return CELL_EINVAL;
|
2014-06-21 16:24:27 +02:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-06-21 02:17:42 +02:00
|
|
|
*sem = Emu.GetIdManager().make<lv2_sema_t>(protocol, max_val, attr->name_u64, initial_val);
|
2015-03-08 04:37:07 +01:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_destroy(u32 sem)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-04-14 04:00:31 +02:00
|
|
|
sys_semaphore.Warning("sys_semaphore_destroy(sem=0x%x)", sem);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto semaphore = Emu.GetIdManager().get<lv2_sema_t>(sem);
|
2015-03-11 16:30:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!semaphore)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
if (semaphore->waiters)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
Emu.GetIdManager().remove<lv2_sema_t>(sem);
|
2015-03-08 04:37:07 +01:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_wait(u32 sem, u64 timeout)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-04-14 04:00:31 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_wait(sem=0x%x, timeout=0x%llx)", sem, timeout);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
const u64 start_time = get_system_time();
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto semaphore = Emu.GetIdManager().get<lv2_sema_t>(sem);
|
2015-03-11 16:30:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!semaphore)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
// protocol is ignored in current implementation
|
2015-03-11 16:30:50 +01:00
|
|
|
semaphore->waiters++;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
while (semaphore->value <= 0)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
if (timeout && get_system_time() - start_time > timeout)
|
|
|
|
|
{
|
2015-03-11 16:30:50 +01:00
|
|
|
semaphore->waiters--;
|
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-03-08 04:37:07 +01:00
|
|
|
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem);
|
2014-06-21 16:24:27 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
2015-03-08 04:37:07 +01:00
|
|
|
|
|
|
|
|
semaphore->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
2014-06-21 16:24:27 +02:00
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
semaphore->value--;
|
2015-03-11 16:30:50 +01:00
|
|
|
semaphore->waiters--;
|
2015-03-08 04:37:07 +01:00
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
return CELL_OK;
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_trywait(u32 sem)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-04-14 04:00:31 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_trywait(sem=0x%x)", sem);
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto semaphore = Emu.GetIdManager().get<lv2_sema_t>(sem);
|
2015-03-11 16:30:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!semaphore)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
if (semaphore->value <= 0 || semaphore->waiters)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_EBUSY;
|
|
|
|
|
}
|
2015-03-08 04:37:07 +01:00
|
|
|
|
|
|
|
|
semaphore->value--;
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_post(u32 sem, s32 count)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2015-04-14 04:00:31 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_post(sem=0x%x, count=%d)", sem, count);
|
2015-03-08 04:37:07 +01:00
|
|
|
|
|
|
|
|
LV2_LOCK;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto semaphore = Emu.GetIdManager().get<lv2_sema_t>(sem);
|
2015-03-11 16:30:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!semaphore)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count < 0)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EINVAL;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2015-03-11 16:30:50 +01:00
|
|
|
const u64 new_value = semaphore->value + count;
|
|
|
|
|
const u64 max_value = semaphore->max + semaphore->waiters;
|
|
|
|
|
|
|
|
|
|
if (new_value > max_value)
|
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
|
|
|
}
|
|
|
|
|
|
2015-03-11 16:30:50 +01:00
|
|
|
semaphore->value += count;
|
|
|
|
|
|
|
|
|
|
if (semaphore->waiters)
|
|
|
|
|
{
|
|
|
|
|
semaphore->cv.notify_all();
|
|
|
|
|
}
|
2013-11-26 01:23:25 +01:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
s32 sys_semaphore_get_value(u32 sem, vm::ptr<s32> count)
|
2013-11-26 01:23:25 +01:00
|
|
|
{
|
2015-04-14 04:00:31 +02:00
|
|
|
sys_semaphore.Log("sys_semaphore_get_value(sem=0x%x, count=*0x%x)", sem, count);
|
2013-11-26 01:23:25 +01:00
|
|
|
|
2014-12-24 00:38:13 +01:00
|
|
|
if (!count)
|
|
|
|
|
{
|
|
|
|
|
return CELL_EFAULT;
|
|
|
|
|
}
|
2014-11-12 23:25:27 +01:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto semaphore = Emu.GetIdManager().get<lv2_sema_t>(sem);
|
2015-03-11 16:30:50 +01:00
|
|
|
|
2015-04-12 22:16:30 +02:00
|
|
|
if (!semaphore)
|
2014-06-21 16:24:27 +02:00
|
|
|
{
|
|
|
|
|
return CELL_ESRCH;
|
|
|
|
|
}
|
2013-11-26 01:23:25 +01:00
|
|
|
|
2015-03-08 04:37:07 +01:00
|
|
|
*count = std::max<s32>(0, semaphore->value - semaphore->waiters);
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|