From 1a1bed2258fdbd8552abc4718d9a92c2435c3c16 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 17 Mar 2014 00:14:46 +0400 Subject: [PATCH] Event flag partial implementation --- rpcs3/Emu/Cell/MFC.h | 4 +- rpcs3/Emu/Cell/SPUInterpreter.h | 22 +++- rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp | 140 +++++++++++++++++++++-- rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h | 10 +- rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp | 2 +- 5 files changed, 162 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index 73bb96dc5f..0cd0a5f43a 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -4,10 +4,10 @@ enum { MFC_PUT_CMD = 0x20, MFC_PUTB_CMD = 0x21, MFC_PUTF_CMD = 0x22, - MFC_PUTR_CMD = 0x30, MFC_PUTRB_CMD = 0x31, MFC_PUTRF_CMD = 0x32, + MFC_PUTR_CMD = 0x30, MFC_PUTRB_CMD = 0x31, MFC_PUTRF_CMD = 0x32, MFC_GET_CMD = 0x40, MFC_GETB_CMD = 0x41, MFC_GETF_CMD = 0x42, MFC_PUTL_CMD = 0x24, MFC_PUTLB_CMD = 0x25, MFC_PUTLF_CMD = 0x26, - MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36, + MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36, MFC_GETL_CMD = 0x44, MFC_GETLB_CMD = 0x45, MFC_GETLF_CMD = 0x46, MFC_GETLLAR_CMD = 0xD0, MFC_PUTLLC_CMD = 0xB4, diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 0b3aba0c25..2b6a4d782a 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -113,14 +113,26 @@ private: } } break; - case 0x102: default: - if (!CPU.SPU.Out_MBox.GetCount()) // the real exit status + case 0x102: + if (!CPU.SPU.Out_MBox.GetCount()) { - ConLog.Warning("STOP: 0x%x (no message)", code); + ConLog.Error("sys_spu_thread_exit (no status, code 0x102)"); } - else if (Ini.HLELogging.GetValue() || code != 0x102) + else if (Ini.HLELogging.GetValue()) { - ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue()); + // the real exit status + ConLog.Write("sys_spu_thread_exit (status=0x%x)", CPU.SPU.Out_MBox.GetValue()); + } + CPU.Stop(); + break; + default: + if (!CPU.SPU.Out_MBox.GetCount()) + { + ConLog.Error("Unknown STOP code: 0x%x (no message)", code); + } + else + { + ConLog.Error("Unknown STOP code: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue()); } CPU.Stop(); break; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp index 4e7bc265af..38f257da4c 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp @@ -6,7 +6,7 @@ SysCallBase sys_event_flag("sys_event_flag"); int 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)", + sys_event_flag.Log("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", eflag_id.GetAddr(), attr.GetAddr(), init); if(!eflag_id.IsGood() || !attr.IsGood()) @@ -30,8 +30,8 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t attr, switch (attr->type.ToBE()) { - case se32(SYS_SYNC_WAITER_SINGLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_SINGLE type"); break; - case se32(SYS_SYNC_WAITER_MULTIPLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_MULTIPLE type"); break; + case se32(SYS_SYNC_WAITER_SINGLE): break; + case se32(SYS_SYNC_WAITER_MULTIPLE): sys_event_flag.Error("TODO: SYS_SYNC_WAITER_MULTIPLE type"); break; default: return CELL_EINVAL; } @@ -57,16 +57,136 @@ int sys_event_flag_destroy(u32 eflag_id) int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout) { - sys_event_flag.Error("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)", + sys_event_flag.Warning("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); - return CELL_OK; + + if (result.IsGood()) 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; + } + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + u32 tid = GetCurrentPPUThread().GetId(); + + ef->waiters.push(tid); + if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.list.GetCount() > 1) + { + ef->waiters.invalidate(tid); + return CELL_EPERM; + } + + u32 counter = 0; + const u32 max_counter = timeout ? (timeout / 1000) : ~0; + + while (true) + { + { + 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))) + { + ef->waiters.invalidate(tid); + + if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) + { + ef->flags &= ~bitptn; + } + else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) + { + ef->flags = 0; + } + + if (result.IsGood()) + { + result = flags; + return CELL_OK; + } + return CELL_EFAULT; + } + } + + Sleep(1); + + if (counter++ > max_counter) + { + ef->waiters.invalidate(tid); + return CELL_ETIMEDOUT; + } + if (Emu.IsStopped()) + { + ConLog.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id); + return CELL_OK; + } + } } int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result) { - sys_event_flag.Error("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)", + sys_event_flag.Warning("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)", eflag_id, bitptn, mode, result.GetAddr()); - return CELL_OK; + + if (result.IsGood()) 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; + } + + event_flag* 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.IsGood()) + { + result = flags; + return CELL_OK; + } + return CELL_EFAULT; + } + + return CELL_EBUSY; } int sys_event_flag_set(u32 eflag_id, u64 bitptn) @@ -76,6 +196,7 @@ int sys_event_flag_set(u32 eflag_id, u64 bitptn) event_flag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + SMutexLocker lock(ef->m_mutex); ef->flags |= bitptn; return CELL_OK; @@ -88,6 +209,7 @@ int sys_event_flag_clear(u32 eflag_id, u64 bitptn) event_flag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + SMutexLocker lock(ef->m_mutex); ef->flags &= bitptn; return CELL_OK; @@ -96,6 +218,10 @@ int sys_event_flag_clear(u32 eflag_id, u64 bitptn) int sys_event_flag_cancel(u32 eflag_id, mem32_t num) { sys_event_flag.Error("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr()); + + event_flag* ef; + if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h index 80983e6a6d..95d8391b00 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h @@ -4,6 +4,12 @@ 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 @@ -18,7 +24,9 @@ struct sys_event_flag_attr struct event_flag { - std::atomic flags; + SMutex m_mutex; + u64 flags; + SleepQueue waiters; const u32 m_protocol; const int m_type; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index ab987cb8cd..ee3d9a846f 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -177,7 +177,7 @@ bool SleepQueue::invalidate(u32 tid) { if (list[i] = tid) { - list[i] = 0; + list.RemoveAt(i); return true; } }