mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 20:15:27 +00:00
sys_event_flag.cpp restored
This commit is contained in:
parent
b89c4fec3e
commit
b00e0fcf69
12 changed files with 615 additions and 600 deletions
|
@ -2,8 +2,6 @@
|
|||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
|
||||
#include "SPUInstrTable.h"
|
||||
#include "SPUDisAsm.h"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/SPUDecoder.h"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Emu/Event.h"
|
||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event_flag.h"
|
||||
#include "Emu/SysCalls/lv2/sys_time.h"
|
||||
#include "MFC.h"
|
||||
#include "Emu/SysCalls/ErrorCodes.h"
|
||||
|
|
|
@ -1,217 +1,5 @@
|
|||
#pragma once
|
||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||
|
||||
#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL)
|
||||
// arbitrary code to prevent "special" zero value in key argument
|
||||
|
||||
enum EventQueueType
|
||||
{
|
||||
SYS_PPU_QUEUE = 1,
|
||||
SYS_SPU_QUEUE = 2,
|
||||
};
|
||||
|
||||
enum EventQueueDestroyMode
|
||||
{
|
||||
// DEFAULT = 0,
|
||||
SYS_EVENT_QUEUE_DESTROY_FORCE = 1,
|
||||
};
|
||||
|
||||
enum EventPortType
|
||||
{
|
||||
SYS_EVENT_PORT_LOCAL = 1,
|
||||
};
|
||||
|
||||
enum EventSourceType
|
||||
{
|
||||
SYS_SPU_THREAD_EVENT_USER = 1,
|
||||
/* SYS_SPU_THREAD_EVENT_DMA = 2, */ // not supported
|
||||
};
|
||||
|
||||
enum EventSourceKey : u64
|
||||
{
|
||||
SYS_SPU_THREAD_EVENT_USER_KEY = 0xFFFFFFFF53505501,
|
||||
/* SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, */
|
||||
};
|
||||
|
||||
struct sys_event_queue_attr
|
||||
{
|
||||
be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
|
||||
be_t<int> type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
u64 name_u64;
|
||||
};
|
||||
};
|
||||
|
||||
struct sys_event_data
|
||||
{
|
||||
be_t<u64> source;
|
||||
be_t<u64> data1;
|
||||
be_t<u64> data2;
|
||||
be_t<u64> data3;
|
||||
};
|
||||
|
||||
struct EventQueue;
|
||||
|
||||
struct EventPort
|
||||
{
|
||||
u64 name; // generated or user-specified code that is passed to sys_event_data struct
|
||||
EventQueue* eq; // event queue this port has been connected to
|
||||
std::mutex m_mutex; // may be locked until the event sending is finished
|
||||
|
||||
EventPort(u64 name = 0)
|
||||
: eq(nullptr)
|
||||
, name(name)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EventRingBuffer
|
||||
{
|
||||
std::vector<sys_event_data> data;
|
||||
std::mutex m_mutex;
|
||||
u32 buf_pos;
|
||||
u32 buf_count;
|
||||
|
||||
public:
|
||||
const u32 size;
|
||||
|
||||
EventRingBuffer(u32 size)
|
||||
: size(size)
|
||||
, buf_pos(0)
|
||||
, buf_count(0)
|
||||
{
|
||||
data.resize(size);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
buf_count = 0;
|
||||
buf_pos = 0;
|
||||
}
|
||||
|
||||
bool push(u64 name, u64 d1, u64 d2, u64 d3)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (buf_count >= size) return false;
|
||||
|
||||
sys_event_data& ref = data[(buf_pos + buf_count++) % size];
|
||||
ref.source = name;
|
||||
ref.data1 = d1;
|
||||
ref.data2 = d2;
|
||||
ref.data3 = d3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pop(sys_event_data& ref)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (!buf_count) return false;
|
||||
|
||||
sys_event_data& from = data[buf_pos];
|
||||
buf_pos = (buf_pos + 1) % size;
|
||||
buf_count--;
|
||||
ref.source = from.source;
|
||||
ref.data1 = from.data1;
|
||||
ref.data2 = from.data2;
|
||||
ref.data3 = from.data3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 pop_all(sys_event_data* ptr, u32 max)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
u32 res = 0;
|
||||
while (buf_count && max)
|
||||
{
|
||||
sys_event_data& from = data[buf_pos];
|
||||
ptr->source = from.source;
|
||||
ptr->data1 = from.data1;
|
||||
ptr->data2 = from.data2;
|
||||
ptr->data3 = from.data3;
|
||||
buf_pos = (buf_pos + 1) % size;
|
||||
buf_count--;
|
||||
max--;
|
||||
ptr++;
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 count() const
|
||||
{
|
||||
return buf_count;
|
||||
}
|
||||
};
|
||||
|
||||
class EventPortList
|
||||
{
|
||||
std::vector<EventPort*> data;
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (u32 i = 0; i < data.size(); i++)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock2(data[i]->m_mutex);
|
||||
data[i]->eq = nullptr; // force all ports to disconnect
|
||||
}
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void add(EventPort* port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
data.push_back(port);
|
||||
}
|
||||
|
||||
void remove(EventPort* port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (u32 i = 0; i < data.size(); i++)
|
||||
{
|
||||
if (data[i] == port)
|
||||
{
|
||||
data.erase(data.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct EventQueue
|
||||
{
|
||||
SleepQueue sq;
|
||||
EventPortList ports;
|
||||
EventRingBuffer events;
|
||||
SMutex owner;
|
||||
|
||||
const union
|
||||
{
|
||||
u64 name_u64;
|
||||
char name[8];
|
||||
};
|
||||
const u32 protocol;
|
||||
const int type;
|
||||
const u64 key;
|
||||
|
||||
EventQueue(u32 protocol, int type, u64 name, u64 key, int size)
|
||||
: type(type)
|
||||
, protocol(protocol)
|
||||
, name_u64(name)
|
||||
, key(key)
|
||||
, events(size) // size: max event count this queue can hold
|
||||
{
|
||||
}
|
||||
};
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
|
||||
class EventManager
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "lv2/lv2Fs.h"
|
||||
#include "lv2/sys_cond.h"
|
||||
#include "lv2/sys_event.h"
|
||||
#include "lv2/sys_event_flag.h"
|
||||
#include "lv2/sys_interrupt.h"
|
||||
#include "lv2/sys_lwcond.h"
|
||||
#include "lv2/sys_lwmutex.h"
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Event.h"
|
||||
|
||||
#include "sys_lwmutex.h"
|
||||
#include "sys_event.h"
|
||||
|
||||
SysCallBase sys_event("sys_event");
|
||||
|
@ -362,323 +361,4 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
|||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// sys_event_flag
|
||||
s32 sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init)
|
||||
{
|
||||
sys_event.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)",
|
||||
eflag_id.GetAddr(), attr.GetAddr(), init);
|
||||
|
||||
switch (attr->protocol.ToBE())
|
||||
{
|
||||
case se32(SYS_SYNC_PRIORITY): break;
|
||||
case se32(SYS_SYNC_RETRY): sys_event.Todo("sys_event_flag_create(): SYS_SYNC_RETRY"); break;
|
||||
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Todo("sys_event_flag_create(): SYS_SYNC_PRIORITY_INHERIT"); break;
|
||||
case se32(SYS_SYNC_FIFO): break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (attr->pshared.ToBE() != se32(0x200))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (attr->type.ToBE())
|
||||
{
|
||||
case se32(SYS_SYNC_WAITER_SINGLE): break;
|
||||
case se32(SYS_SYNC_WAITER_MULTIPLE): break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
eflag_id = sys_event.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type));
|
||||
|
||||
sys_event.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d",
|
||||
std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, eflag_id.GetValue());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_destroy(u32 eflag_id)
|
||||
{
|
||||
sys_event.Warning("sys_event_flag_destroy(eflag_id=%d)", eflag_id);
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
if (ef->waiters.size()) // ???
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(eflag_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
|
||||
eflag_id, bitptn, mode, result.GetAddr(), timeout);
|
||||
|
||||
if (result.GetAddr()) result = 0;
|
||||
|
||||
switch (mode & 0xf)
|
||||
{
|
||||
case SYS_EVENT_FLAG_WAIT_AND: break;
|
||||
case SYS_EVENT_FLAG_WAIT_OR: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (mode & ~0xf)
|
||||
{
|
||||
case 0: break; // ???
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
EventFlagWaiter rec;
|
||||
rec.bitptn = bitptn;
|
||||
rec.mode = mode;
|
||||
rec.tid = tid;
|
||||
ef->waiters.push_back(rec);
|
||||
|
||||
if (ef->check() == tid)
|
||||
{
|
||||
u64 flags = ef->flags;
|
||||
|
||||
ef->waiters.erase(ef->waiters.end() - 1);
|
||||
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (ef->signal.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
u64 flags = ef->flags;
|
||||
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
if (ef->waiters[i].tid == tid)
|
||||
{
|
||||
ef->waiters.erase(ef->waiters.begin() +i);
|
||||
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.unlock(tid, target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->signal.unlock(tid);
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
ef->signal.unlock(tid);
|
||||
return CELL_ECANCELED;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
if (ef->waiters[i].tid == tid)
|
||||
{
|
||||
ef->waiters.erase(ef->waiters.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(HLE, "sys_event_flag_wait(id=%d) aborted", eflag_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)",
|
||||
eflag_id, bitptn, mode, result.GetAddr());
|
||||
|
||||
if (result.GetAddr()) result = 0;
|
||||
|
||||
switch (mode & 0xf)
|
||||
{
|
||||
case SYS_EVENT_FLAG_WAIT_AND: break;
|
||||
case SYS_EVENT_FLAG_WAIT_OR: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (mode & ~0xf)
|
||||
{
|
||||
case 0: break; // ???
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
u64 flags = ef->flags;
|
||||
|
||||
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) ||
|
||||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn)))
|
||||
{
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_set(u32 eflag_id, u64 bitptn)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= bitptn;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
ef->flags &= bitptn;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_cancel(u32 eflag_id, mem32_t num)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr());
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
std::vector<u32> tids;
|
||||
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
tids.resize(ef->waiters.size());
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
tids[i] = ef->waiters[i].tid;
|
||||
}
|
||||
ef->waiters.clear();
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < tids.size(); i++)
|
||||
{
|
||||
ef->signal.lock(tids[i]);
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(HLE, "sys_event_flag_cancel(id=%d) aborted", eflag_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (num.GetAddr()) num = tids.size();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_get(u32 eflag_id, mem64_t flags)
|
||||
{
|
||||
sys_event.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.GetAddr());
|
||||
|
||||
EventFlag* ef;
|
||||
if(!sys_event.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
flags = ef->flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
|
@ -1,77 +1,216 @@
|
|||
#pragma once
|
||||
#include "Emu/Event.h"
|
||||
|
||||
enum
|
||||
#include "sys_lwmutex.h"
|
||||
|
||||
#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL)
|
||||
// arbitrary code to prevent "special" zero value in key argument
|
||||
|
||||
enum EventQueueType
|
||||
{
|
||||
SYS_SYNC_WAITER_SINGLE = 0x10000,
|
||||
SYS_SYNC_WAITER_MULTIPLE = 0x20000,
|
||||
|
||||
SYS_EVENT_FLAG_WAIT_AND = 0x01,
|
||||
SYS_EVENT_FLAG_WAIT_OR = 0x02,
|
||||
|
||||
SYS_EVENT_FLAG_WAIT_CLEAR = 0x10,
|
||||
SYS_EVENT_FLAG_WAIT_CLEAR_ALL = 0x20,
|
||||
SYS_PPU_QUEUE = 1,
|
||||
SYS_SPU_QUEUE = 2,
|
||||
};
|
||||
|
||||
struct sys_event_flag_attr
|
||||
enum EventQueueDestroyMode
|
||||
{
|
||||
be_t<u32> protocol;
|
||||
be_t<u32> pshared;
|
||||
be_t<u64> ipc_key;
|
||||
be_t<int> flags;
|
||||
be_t<int> type;
|
||||
char name[8];
|
||||
// DEFAULT = 0,
|
||||
SYS_EVENT_QUEUE_DESTROY_FORCE = 1,
|
||||
};
|
||||
|
||||
struct EventFlagWaiter
|
||||
enum EventPortType
|
||||
{
|
||||
u32 tid;
|
||||
u32 mode;
|
||||
u64 bitptn;
|
||||
SYS_EVENT_PORT_LOCAL = 1,
|
||||
};
|
||||
|
||||
struct EventFlag
|
||||
enum EventSourceType
|
||||
{
|
||||
SMutex m_mutex;
|
||||
u64 flags;
|
||||
std::vector<EventFlagWaiter> waiters;
|
||||
SMutex signal;
|
||||
const u32 m_protocol;
|
||||
const int m_type;
|
||||
SYS_SPU_THREAD_EVENT_USER = 1,
|
||||
/* SYS_SPU_THREAD_EVENT_DMA = 2, */ // not supported
|
||||
};
|
||||
|
||||
EventFlag(u64 pattern, u32 protocol, int type)
|
||||
: flags(pattern)
|
||||
, m_protocol(protocol)
|
||||
, m_type(type)
|
||||
enum EventSourceKey : u64
|
||||
{
|
||||
SYS_SPU_THREAD_EVENT_USER_KEY = 0xFFFFFFFF53505501,
|
||||
/* SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, */
|
||||
};
|
||||
|
||||
struct sys_event_queue_attr
|
||||
{
|
||||
be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
|
||||
be_t<int> type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
u64 name_u64;
|
||||
};
|
||||
};
|
||||
|
||||
struct sys_event_data
|
||||
{
|
||||
be_t<u64> source;
|
||||
be_t<u64> data1;
|
||||
be_t<u64> data2;
|
||||
be_t<u64> data3;
|
||||
};
|
||||
|
||||
struct EventQueue;
|
||||
|
||||
struct EventPort
|
||||
{
|
||||
u64 name; // generated or user-specified code that is passed to sys_event_data struct
|
||||
EventQueue* eq; // event queue this port has been connected to
|
||||
std::mutex m_mutex; // may be locked until the event sending is finished
|
||||
|
||||
EventPort(u64 name = 0)
|
||||
: eq(nullptr)
|
||||
, name(name)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
u32 check()
|
||||
class EventRingBuffer
|
||||
{
|
||||
std::vector<sys_event_data> data;
|
||||
std::mutex m_mutex;
|
||||
u32 buf_pos;
|
||||
u32 buf_count;
|
||||
|
||||
public:
|
||||
const u32 size;
|
||||
|
||||
EventRingBuffer(u32 size)
|
||||
: size(size)
|
||||
, buf_pos(0)
|
||||
, buf_count(0)
|
||||
{
|
||||
SleepQueue sq; // TODO: implement without SleepQueue
|
||||
data.resize(size);
|
||||
}
|
||||
|
||||
u32 target = 0;
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
buf_count = 0;
|
||||
buf_pos = 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < waiters.size(); i++)
|
||||
bool push(u64 name, u64 d1, u64 d2, u64 d3)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (buf_count >= size) return false;
|
||||
|
||||
sys_event_data& ref = data[(buf_pos + buf_count++) % size];
|
||||
ref.source = name;
|
||||
ref.data1 = d1;
|
||||
ref.data2 = d2;
|
||||
ref.data3 = d3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pop(sys_event_data& ref)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (!buf_count) return false;
|
||||
|
||||
sys_event_data& from = data[buf_pos];
|
||||
buf_pos = (buf_pos + 1) % size;
|
||||
buf_count--;
|
||||
ref.source = from.source;
|
||||
ref.data1 = from.data1;
|
||||
ref.data2 = from.data2;
|
||||
ref.data3 = from.data3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 pop_all(sys_event_data* ptr, u32 max)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
u32 res = 0;
|
||||
while (buf_count && max)
|
||||
{
|
||||
if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) ||
|
||||
((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn)))
|
||||
sys_event_data& from = data[buf_pos];
|
||||
ptr->source = from.source;
|
||||
ptr->data1 = from.data1;
|
||||
ptr->data2 = from.data2;
|
||||
ptr->data3 = from.data3;
|
||||
buf_pos = (buf_pos + 1) % size;
|
||||
buf_count--;
|
||||
max--;
|
||||
ptr++;
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 count() const
|
||||
{
|
||||
return buf_count;
|
||||
}
|
||||
};
|
||||
|
||||
class EventPortList
|
||||
{
|
||||
std::vector<EventPort*> data;
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (u32 i = 0; i < data.size(); i++)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock2(data[i]->m_mutex);
|
||||
data[i]->eq = nullptr; // force all ports to disconnect
|
||||
}
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void add(EventPort* port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
data.push_back(port);
|
||||
}
|
||||
|
||||
void remove(EventPort* port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (u32 i = 0; i < data.size(); i++)
|
||||
{
|
||||
if (data[i] == port)
|
||||
{
|
||||
if (m_protocol == SYS_SYNC_FIFO)
|
||||
{
|
||||
target = waiters[i].tid;
|
||||
break;
|
||||
}
|
||||
sq.list.push_back(waiters[i].tid);
|
||||
data.erase(data.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (m_protocol == SYS_SYNC_PRIORITY)
|
||||
{
|
||||
target = sq.pop_prio();
|
||||
}
|
||||
struct EventQueue
|
||||
{
|
||||
SleepQueue sq;
|
||||
EventPortList ports;
|
||||
EventRingBuffer events;
|
||||
SMutex owner;
|
||||
|
||||
return target;
|
||||
const union
|
||||
{
|
||||
u64 name_u64;
|
||||
char name[8];
|
||||
};
|
||||
const u32 protocol;
|
||||
const int type;
|
||||
const u64 key;
|
||||
|
||||
EventQueue(u32 protocol, int type, u64 name, u64 key, int size)
|
||||
: type(type)
|
||||
, protocol(protocol)
|
||||
, name_u64(name)
|
||||
, key(key)
|
||||
, events(size) // size: max event count this queue can hold
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -87,12 +226,3 @@ s32 sys_event_port_destroy(u32 eport_id);
|
|||
s32 sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id);
|
||||
s32 sys_event_port_disconnect(u32 eport_id);
|
||||
s32 sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3);
|
||||
|
||||
s32 sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init);
|
||||
s32 sys_event_flag_destroy(u32 eflag_id);
|
||||
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout);
|
||||
s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result);
|
||||
s32 sys_event_flag_set(u32 eflag_id, u64 bitptn);
|
||||
s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn);
|
||||
s32 sys_event_flag_cancel(u32 eflag_id, mem32_t num);
|
||||
s32 sys_event_flag_get(u32 eflag_id, mem64_t flags);
|
||||
|
|
329
rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp
Normal file
329
rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp
Normal file
|
@ -0,0 +1,329 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "sys_event_flag.h"
|
||||
|
||||
SysCallBase sys_event_flag("sys_event_flag");
|
||||
|
||||
s32 sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init)
|
||||
{
|
||||
sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)",
|
||||
eflag_id.GetAddr(), attr.GetAddr(), init);
|
||||
|
||||
switch (attr->protocol.ToBE())
|
||||
{
|
||||
case se32(SYS_SYNC_PRIORITY): break;
|
||||
case se32(SYS_SYNC_RETRY): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_RETRY"); break;
|
||||
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_PRIORITY_INHERIT"); break;
|
||||
case se32(SYS_SYNC_FIFO): break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (attr->pshared.ToBE() != se32(0x200))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (attr->type.ToBE())
|
||||
{
|
||||
case se32(SYS_SYNC_WAITER_SINGLE): break;
|
||||
case se32(SYS_SYNC_WAITER_MULTIPLE): break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
eflag_id = sys_event_flag.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type));
|
||||
|
||||
sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d",
|
||||
std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, eflag_id.GetValue());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_destroy(u32 eflag_id)
|
||||
{
|
||||
sys_event_flag.Warning("sys_event_flag_destroy(eflag_id=%d)", eflag_id);
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
if (ef->waiters.size()) // ???
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(eflag_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
|
||||
eflag_id, bitptn, mode, result.GetAddr(), timeout);
|
||||
|
||||
if (result.GetAddr()) result = 0;
|
||||
|
||||
switch (mode & 0xf)
|
||||
{
|
||||
case SYS_EVENT_FLAG_WAIT_AND: break;
|
||||
case SYS_EVENT_FLAG_WAIT_OR: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (mode & ~0xf)
|
||||
{
|
||||
case 0: break; // ???
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
EventFlagWaiter rec;
|
||||
rec.bitptn = bitptn;
|
||||
rec.mode = mode;
|
||||
rec.tid = tid;
|
||||
ef->waiters.push_back(rec);
|
||||
|
||||
if (ef->check() == tid)
|
||||
{
|
||||
u64 flags = ef->flags;
|
||||
|
||||
ef->waiters.erase(ef->waiters.end() - 1);
|
||||
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (ef->signal.unlock(tid, tid) == SMR_OK)
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
u64 flags = ef->flags;
|
||||
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
if (ef->waiters[i].tid == tid)
|
||||
{
|
||||
ef->waiters.erase(ef->waiters.begin() + i);
|
||||
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.unlock(tid, target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->signal.unlock(tid);
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
ef->signal.unlock(tid);
|
||||
return CELL_ECANCELED;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
if (ef->waiters[i].tid == tid)
|
||||
{
|
||||
ef->waiters.erase(ef->waiters.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(HLE, "sys_event_flag_wait(id=%d) aborted", eflag_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)",
|
||||
eflag_id, bitptn, mode, result.GetAddr());
|
||||
|
||||
if (result.GetAddr()) result = 0;
|
||||
|
||||
switch (mode & 0xf)
|
||||
{
|
||||
case SYS_EVENT_FLAG_WAIT_AND: break;
|
||||
case SYS_EVENT_FLAG_WAIT_OR: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (mode & ~0xf)
|
||||
{
|
||||
case 0: break; // ???
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
|
||||
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
|
||||
u64 flags = ef->flags;
|
||||
|
||||
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) ||
|
||||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn)))
|
||||
{
|
||||
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
|
||||
{
|
||||
ef->flags &= ~bitptn;
|
||||
}
|
||||
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
|
||||
{
|
||||
ef->flags = 0;
|
||||
}
|
||||
|
||||
if (result.GetAddr()) result = flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_set(u32 eflag_id, u64 bitptn)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= bitptn;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
ef->flags &= bitptn;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_cancel(u32 eflag_id, mem32_t num)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr());
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
std::vector<u32> tids;
|
||||
|
||||
{
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
tids.resize(ef->waiters.size());
|
||||
for (u32 i = 0; i < ef->waiters.size(); i++)
|
||||
{
|
||||
tids[i] = ef->waiters[i].tid;
|
||||
}
|
||||
ef->waiters.clear();
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < tids.size(); i++)
|
||||
{
|
||||
ef->signal.lock(tids[i]);
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(HLE, "sys_event_flag_cancel(id=%d) aborted", eflag_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (num.GetAddr()) num = tids.size();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_get(u32 eflag_id, mem64_t flags)
|
||||
{
|
||||
sys_event_flag.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.GetAddr());
|
||||
|
||||
EventFlag* ef;
|
||||
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
|
||||
|
||||
SMutexLocker lock(ef->m_mutex);
|
||||
flags = ef->flags;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
84
rpcs3/Emu/SysCalls/lv2/sys_event_flag.h
Normal file
84
rpcs3/Emu/SysCalls/lv2/sys_event_flag.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_WAITER_SINGLE = 0x10000,
|
||||
SYS_SYNC_WAITER_MULTIPLE = 0x20000,
|
||||
|
||||
SYS_EVENT_FLAG_WAIT_AND = 0x01,
|
||||
SYS_EVENT_FLAG_WAIT_OR = 0x02,
|
||||
|
||||
SYS_EVENT_FLAG_WAIT_CLEAR = 0x10,
|
||||
SYS_EVENT_FLAG_WAIT_CLEAR_ALL = 0x20,
|
||||
};
|
||||
|
||||
struct sys_event_flag_attr
|
||||
{
|
||||
be_t<u32> protocol;
|
||||
be_t<u32> pshared;
|
||||
be_t<u64> ipc_key;
|
||||
be_t<int> flags;
|
||||
be_t<int> type;
|
||||
char name[8];
|
||||
};
|
||||
|
||||
struct EventFlagWaiter
|
||||
{
|
||||
u32 tid;
|
||||
u32 mode;
|
||||
u64 bitptn;
|
||||
};
|
||||
|
||||
struct EventFlag
|
||||
{
|
||||
SMutex m_mutex;
|
||||
u64 flags;
|
||||
std::vector<EventFlagWaiter> waiters;
|
||||
SMutex signal;
|
||||
const u32 m_protocol;
|
||||
const int m_type;
|
||||
|
||||
EventFlag(u64 pattern, u32 protocol, int type)
|
||||
: flags(pattern)
|
||||
, m_protocol(protocol)
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
u32 check()
|
||||
{
|
||||
SleepQueue sq; // TODO: implement without SleepQueue
|
||||
|
||||
u32 target = 0;
|
||||
|
||||
for (u32 i = 0; i < waiters.size(); i++)
|
||||
{
|
||||
if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) ||
|
||||
((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn)))
|
||||
{
|
||||
if (m_protocol == SYS_SYNC_FIFO)
|
||||
{
|
||||
target = waiters[i].tid;
|
||||
break;
|
||||
}
|
||||
sq.list.push_back(waiters[i].tid);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_protocol == SYS_SYNC_PRIORITY)
|
||||
{
|
||||
target = sq.pop_prio();
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
};
|
||||
|
||||
s32 sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init);
|
||||
s32 sys_event_flag_destroy(u32 eflag_id);
|
||||
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout);
|
||||
s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result);
|
||||
s32 sys_event_flag_set(u32 eflag_id, u64 bitptn);
|
||||
s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn);
|
||||
s32 sys_event_flag_cancel(u32 eflag_id, mem32_t num);
|
||||
s32 sys_event_flag_get(u32 eflag_id, mem64_t flags);
|
|
@ -95,6 +95,7 @@
|
|||
<ClCompile Include="Emu\SysCalls\lv2\lv2Fs.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_cond.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_event.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_interrupt.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_lwcond.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_lwmutex.cpp" />
|
||||
|
@ -321,6 +322,7 @@
|
|||
<ClInclude Include="Emu\SysCalls\lv2\lv2Fs.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_cond.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_event.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_interrupt.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_lwcond.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_lwmutex.h" />
|
||||
|
@ -568,4 +570,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -587,6 +587,9 @@
|
|||
<ClCompile Include="Emu\RSX\RSXThread.cpp">
|
||||
<Filter>Emu\RSX</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
@ -1117,5 +1120,8 @@
|
|||
<ClInclude Include="Emu\RSX\GCM.h">
|
||||
<Filter>Emu\RSX</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
Loading…
Add table
Reference in a new issue