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

358 lines
6.3 KiB
C++
Raw Normal View History

2014-08-08 17:55:12 +02:00
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
2015-03-06 23:58:42 +01:00
#include "Emu/IdManager.h"
2014-08-08 17:55:12 +02:00
#include "Emu/SysCalls/SysCalls.h"
2014-12-24 17:09:32 +01: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"
2015-03-05 22:29:05 +01:00
#include "sys_time.h"
2014-08-08 17:55:12 +02:00
#include "sys_event_flag.h"
SysCallBase sys_event_flag("sys_event_flag");
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attr> attr, u64 init)
2014-08-23 02:16:54 +02:00
{
2015-03-05 22:29:05 +01:00
sys_event_flag.Warning("sys_event_flag_create(id=*0x%x, attr=*0x%x, init=0x%llx)", id, attr, init);
2014-08-23 02:16:54 +02:00
2015-03-05 22:29:05 +01:00
if (!id || !attr)
{
return CELL_EFAULT;
}
2015-03-05 22:29:05 +01:00
const u32 protocol = attr->protocol;
2015-03-05 22:29:05 +01:00
switch (protocol)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
case SYS_SYNC_FIFO: break;
2015-03-08 03:32:41 +01:00
case SYS_SYNC_RETRY: break;
case SYS_SYNC_PRIORITY: break;
case SYS_SYNC_PRIORITY_INHERIT: break;
2015-03-06 23:10:04 +01:00
default: sys_event_flag.Error("sys_event_flag_create(): unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL;
2014-08-08 17:55:12 +02:00
}
2015-03-06 23:10:04 +01:00
if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data())
{
2015-03-06 23:10:04 +01:00
sys_event_flag.Error("sys_event_flag_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
2014-08-08 17:55:12 +02:00
return CELL_EINVAL;
}
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
const u32 type = attr->type;
switch (type)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
case SYS_SYNC_WAITER_SINGLE: break;
case SYS_SYNC_WAITER_MULTIPLE: break;
2015-03-06 23:10:04 +01:00
default: sys_event_flag.Error("sys_event_flag_create(): unknown type (0x%x)", attr->type); return CELL_EINVAL;
2014-08-08 17:55:12 +02:00
}
*id = Emu.GetIdManager().make<lv2_event_flag_t>(init, protocol, type, attr->name_u64);
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_destroy(u32 id)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Warning("sys_event_flag_destroy(id=0x%x)", id);
2015-03-05 22:29:05 +01:00
LV2_LOCK;
2014-08-08 17:55:12 +02:00
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2014-08-08 17:55:12 +02:00
2015-04-12 03:36:25 +02:00
if (!ef)
2015-03-05 22:29:05 +01:00
{
return CELL_ESRCH;
}
if (ef->waiters)
2014-08-08 17:55:12 +02:00
{
return CELL_EBUSY;
}
Emu.GetIdManager().remove<lv2_event_flag_t>(id);
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout);
2015-03-05 22:29:05 +01:00
const u64 start_time = get_system_time();
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
LV2_LOCK;
if (result)
{
*result = 0;
}
2014-08-08 17:55:12 +02:00
switch (mode & 0xf)
{
case SYS_EVENT_FLAG_WAIT_AND: break;
case SYS_EVENT_FLAG_WAIT_OR: break;
default: return CELL_EINVAL;
}
switch (mode & ~0xf)
{
2015-03-05 22:29:05 +01:00
case 0: break;
2014-08-08 17:55:12 +02:00
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
default: return CELL_EINVAL;
}
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2015-03-05 22:29:05 +01:00
2015-04-12 03:36:25 +02:00
if (!ef)
2015-03-05 22:29:05 +01:00
{
return CELL_ESRCH;
}
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
if (ef->type == SYS_SYNC_WAITER_SINGLE && ef->waiters)
{
return CELL_EPERM;
}
2014-08-08 17:55:12 +02:00
2015-03-11 16:30:50 +01:00
while (ef->cancelled)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
// wait until other threads return CELL_ECANCELED (to prevent modifying bit pattern)
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
// protocol is ignored in current implementation
ef->waiters++;
2014-12-23 00:31:11 +01:00
2015-03-05 22:29:05 +01:00
while (true)
{
if (result)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
*result = ef->flags;
2014-08-08 17:55:12 +02:00
}
2014-12-23 00:31:11 +01:00
2015-03-05 22:29:05 +01:00
if (mode & SYS_EVENT_FLAG_WAIT_AND && (ef->flags & bitptn) == bitptn)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
break;
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
if (mode & SYS_EVENT_FLAG_WAIT_OR && ef->flags & bitptn)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
break;
}
2014-08-08 17:55:12 +02:00
2015-03-11 16:30:50 +01:00
if (ef->cancelled)
2015-03-05 22:29:05 +01:00
{
2015-03-11 16:30:50 +01:00
if (!--ef->cancelled)
2015-03-06 23:10:04 +01:00
{
ef->cv.notify_all();
}
2014-08-08 17:55:12 +02:00
return CELL_ECANCELED;
}
2015-03-05 22:29:05 +01:00
if (timeout && get_system_time() - start_time > timeout)
2014-08-08 17:55:12 +02:00
{
2015-03-11 16:30:50 +01:00
ef->waiters--;
2014-08-08 17:55:12 +02:00
return CELL_ETIMEDOUT;
}
2014-12-23 00:31:11 +01:00
2014-08-08 17:55:12 +02:00
if (Emu.IsStopped())
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Warning("sys_event_flag_wait(id=0x%x) aborted", id);
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{
ef->flags &= ~bitptn;
}
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{
ef->flags = 0;
}
2015-03-11 16:30:50 +01:00
if (--ef->waiters && ef->flags)
2015-03-05 22:29:05 +01:00
{
ef->cv.notify_one();
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
return CELL_OK;
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_trywait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_trywait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x)", id, bitptn, mode, result);
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
LV2_LOCK;
if (result)
{
*result = 0;
}
2014-08-08 17:55:12 +02:00
switch (mode & 0xf)
{
case SYS_EVENT_FLAG_WAIT_AND: break;
case SYS_EVENT_FLAG_WAIT_OR: break;
default: return CELL_EINVAL;
}
switch (mode & ~0xf)
{
2015-03-05 22:29:05 +01:00
case 0: break;
2014-08-08 17:55:12 +02:00
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
default: return CELL_EINVAL;
}
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2014-08-08 17:55:12 +02:00
2015-04-12 03:36:25 +02:00
if (!ef)
2015-03-05 22:29:05 +01:00
{
return CELL_ESRCH;
}
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
if (!((mode & SYS_EVENT_FLAG_WAIT_AND) && (ef->flags & bitptn) == bitptn) && !((mode & SYS_EVENT_FLAG_WAIT_OR) && (ef->flags & bitptn)))
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
return CELL_EBUSY;
}
2014-08-08 17:55:12 +02:00
2015-03-11 16:30:50 +01:00
while (ef->cancelled)
2015-03-05 22:29:05 +01:00
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{
ef->flags &= ~bitptn;
}
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{
ef->flags &= 0;
}
if (result)
{
*result = ef->flags;
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
return CELL_OK;
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_set(u32 id, u64 bitptn)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_set(id=0x%x, bitptn=0x%llx)", id, bitptn);
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
LV2_LOCK;
2014-08-08 17:55:12 +02:00
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2014-08-08 17:55:12 +02:00
2015-04-12 03:36:25 +02:00
if (!ef)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
return CELL_ESRCH;
2014-08-08 17:55:12 +02:00
}
2015-03-05 22:29:05 +01:00
2015-03-11 16:30:50 +01:00
while (ef->cancelled)
2015-03-05 22:29:05 +01:00
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
ef->flags |= bitptn;
2015-03-11 16:30:50 +01:00
if (ef->waiters)
{
ef->cv.notify_all();
}
2015-03-05 22:29:05 +01:00
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_clear(u32 id, u64 bitptn)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_clear(id=0x%x, bitptn=0x%llx)", id, bitptn);
2015-03-05 22:29:05 +01:00
LV2_LOCK;
2014-08-08 17:55:12 +02:00
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2015-03-05 22:29:05 +01:00
2015-04-12 03:36:25 +02:00
if (!ef)
2015-03-05 22:29:05 +01:00
{
return CELL_ESRCH;
}
2015-03-11 16:30:50 +01:00
while (ef->cancelled)
2015-03-05 22:29:05 +01:00
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
2014-08-08 17:55:12 +02:00
ef->flags &= bitptn;
2015-03-05 22:29:05 +01:00
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_cancel(id=0x%x, num=*0x%x)", id, num);
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
LV2_LOCK;
2014-08-08 17:55:12 +02:00
2015-03-05 22:29:05 +01:00
if (num)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
*num = 0;
2014-08-08 17:55:12 +02:00
}
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2015-03-05 22:29:05 +01:00
2015-04-12 03:36:25 +02:00
if (!ef)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
return CELL_ESRCH;
2014-08-08 17:55:12 +02:00
}
2015-03-11 16:30:50 +01:00
while (ef->cancelled)
2014-08-08 17:55:12 +02:00
{
2015-03-05 22:29:05 +01:00
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
2014-08-08 17:55:12 +02:00
}
2014-12-23 00:31:11 +01:00
if (num)
{
2015-03-05 22:29:05 +01:00
*num = ef->waiters;
2014-12-23 00:31:11 +01:00
}
2014-08-08 17:55:12 +02:00
2015-03-11 16:30:50 +01:00
if ((ef->cancelled = ef->waiters.exchange(0)))
{
ef->cv.notify_all();
}
2014-08-08 17:55:12 +02:00
return CELL_OK;
}
2015-03-05 22:29:05 +01:00
s32 sys_event_flag_get(u32 id, vm::ptr<u64> flags)
2014-08-08 17:55:12 +02:00
{
2015-04-14 04:00:31 +02:00
sys_event_flag.Log("sys_event_flag_get(id=0x%x, flags=*0x%x)", id, flags);
2015-03-05 22:29:05 +01:00
LV2_LOCK;
2014-08-08 17:55:12 +02:00
if (!flags)
{
return CELL_EFAULT;
}
const auto ef = Emu.GetIdManager().get<lv2_event_flag_t>(id);
2015-03-05 22:29:05 +01:00
2015-04-12 03:36:25 +02:00
if (!ef)
2015-03-05 22:29:05 +01:00
{
*flags = 0;
return CELL_ESRCH;
}
*flags = ef->flags;
2014-08-08 17:55:12 +02:00
return CELL_OK;
2015-03-05 22:29:05 +01:00
}