diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 2337f6d0e1..a1ad6c258a 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -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" diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index fe005b6804..72a59dc6cf 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -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" diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 235b73700c..559861ddd3 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -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" diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 664f96cc0f..6a4e1ef40e 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.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" diff --git a/rpcs3/Emu/Event.h b/rpcs3/Emu/Event.h index 235b924daf..fe4a2147b7 100644 --- a/rpcs3/Emu/Event.h +++ b/rpcs3/Emu/Event.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 protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO - be_t type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE - union - { - char name[8]; - u64 name_u64; - }; -}; - -struct sys_event_data -{ - be_t source; - be_t data1; - be_t data2; - be_t 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 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 lock(m_mutex); - buf_count = 0; - buf_pos = 0; - } - - bool push(u64 name, u64 d1, u64 d2, u64 d3) - { - std::lock_guard 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 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 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 data; - std::mutex m_mutex; - -public: - - void clear() - { - std::lock_guard lock(m_mutex); - for (u32 i = 0; i < data.size(); i++) - { - std::lock_guard lock2(data[i]->m_mutex); - data[i]->eq = nullptr; // force all ports to disconnect - } - data.clear(); - } - - void add(EventPort* port) - { - std::lock_guard lock(m_mutex); - data.push_back(port); - } - - void remove(EventPort* port) - { - std::lock_guard 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 { diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 61629ba897..bd3391340d 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -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" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index c49347d4ff..838a53ebca 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -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 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 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; -} +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/SysCalls/lv2/sys_event.h index 09866991e7..984e3bd762 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.h @@ -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 protocol; - be_t pshared; - be_t ipc_key; - be_t flags; - be_t 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 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 protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO + be_t type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE + union + { + char name[8]; + u64 name_u64; + }; +}; + +struct sys_event_data +{ + be_t source; + be_t data1; + be_t data2; + be_t 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 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 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 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 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 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 data; + std::mutex m_mutex; + +public: + + void clear() + { + std::lock_guard lock(m_mutex); + for (u32 i = 0; i < data.size(); i++) + { + std::lock_guard lock2(data[i]->m_mutex); + data[i]->eq = nullptr; // force all ports to disconnect + } + data.clear(); + } + + void add(EventPort* port) + { + std::lock_guard lock(m_mutex); + data.push_back(port); + } + + void remove(EventPort* port) + { + std::lock_guard 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 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); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp new file mode 100644 index 0000000000..8a2b1374e5 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -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 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 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; +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h new file mode 100644 index 0000000000..48901ba572 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -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 protocol; + be_t pshared; + be_t ipc_key; + be_t flags; + be_t type; + char name[8]; +}; + +struct EventFlagWaiter +{ + u32 tid; + u32 mode; + u64 bitptn; +}; + +struct EventFlag +{ + SMutex m_mutex; + u64 flags; + std::vector 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 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); \ No newline at end of file diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 5a92f945e1..f14bade857 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -95,6 +95,7 @@ + @@ -321,6 +322,7 @@ + @@ -568,4 +570,4 @@ - + \ No newline at end of file diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index e976ffed57..0a1d6e9701 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -587,6 +587,9 @@ Emu\RSX + + Emu\SysCalls\lv2 + @@ -1117,5 +1120,8 @@ Emu\RSX + + Emu\SysCalls\lv2 + - + \ No newline at end of file