From c4d9223034ff2be401d49794e603b2599ea02afd Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 17 Mar 2014 19:07:47 +0400 Subject: [PATCH] event flag improvement (not finished) Fixed empty SPU thread name issue --- rpcs3/Emu/Cell/SPUThread.h | 59 ++++++- rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp | 10 +- rpcs3/Emu/SysCalls/lv2/SC_Condition.h | 2 +- rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp | 190 ++++++++++++++++++----- rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h | 42 ++++- rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp | 17 +- 6 files changed, 267 insertions(+), 53 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 527be9bfc7..ba260eb360 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -896,9 +896,66 @@ public: SPU.In_MBox.PushUncond(CELL_OK); return; } + else if (code = 128) + { + /* ===== sys_event_flag_set_bit ===== */ + u32 flag = v & 0xffffff; + + u32 data; + if (!SPU.Out_MBox.Pop(data)) + { + ConLog.Error("sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag); + return; + } + + if (flag > 63) + { + ConLog.Error("sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag); + return; + } + + //if (Ini.HLELogging.GetValue()) + { + ConLog.Warning("sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag); + } + + EventFlag* ef; + if (!Emu.GetIdManager().GetIDData(data, ef)) + { + ConLog.Error("sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); + SPU.In_MBox.PushUncond(CELL_ESRCH); + return; + } + + u32 tid = GetCurrentCPUThread()->GetId(); + + ef->m_mutex.lock(tid); + ef->flags |= (u64)1 << flag; + 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); + } + + SPU.In_MBox.PushUncond(CELL_OK); + return; + } else { - ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x)", v); + u32 data; + if (SPU.Out_MBox.Pop(data)) + { + ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data); + } + else + { + ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x)", v); + } SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? return; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp index cc6a1d7c9d..0fe7b5856e 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp @@ -74,7 +74,7 @@ int sys_cond_signal(u32 cond_id) if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) { - cond->cond.lock(target); + cond->signal.lock(target); if (Emu.IsStopped()) { @@ -99,7 +99,7 @@ int sys_cond_signal_all(u32 cond_id) while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) { - cond->cond.lock(target); + cond->signal.lock(target); if (Emu.IsStopped()) { @@ -134,7 +134,7 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id) u32 target = thread_id; { - cond->cond.lock(target); + cond->signal.lock(target); } if (Emu.IsStopped()) @@ -173,11 +173,11 @@ int sys_cond_wait(u32 cond_id, u64 timeout) while (true) { - if (cond->cond.GetOwner() == tid) + if (cond->signal.GetOwner() == tid) { mutex->m_mutex.lock(tid); mutex->recursive = 1; - cond->cond.unlock(tid); + cond->signal.unlock(tid); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.h b/rpcs3/Emu/SysCalls/lv2/SC_Condition.h index 460923a504..a8d7472c63 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.h @@ -16,7 +16,7 @@ struct sys_cond_attribute struct Cond { Mutex* mutex; // associated with mutex - SMutex cond; + SMutex signal; SleepQueue m_queue; Cond(Mutex* mutex, u64 name) diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.cpp index 38f257da4c..72ac3ebef6 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.Log("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", + 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); if(!eflag_id.IsGood() || !attr.IsGood()) @@ -16,10 +16,10 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t attr, switch (attr->protocol.ToBE()) { - case se32(SYS_SYNC_PRIORITY): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; + case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_event_flag.Warning("TODO: SYS_SYNC_RETRY attr"); break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break; - case se32(SYS_SYNC_FIFO): sys_event_flag.Warning("TODO: SYS_SYNC_FIFO attr"); break; + case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } @@ -31,11 +31,11 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t attr, switch (attr->type.ToBE()) { case se32(SYS_SYNC_WAITER_SINGLE): break; - case se32(SYS_SYNC_WAITER_MULTIPLE): sys_event_flag.Error("TODO: SYS_SYNC_WAITER_MULTIPLE type"); break; + case se32(SYS_SYNC_WAITER_MULTIPLE): break; default: return CELL_EINVAL; } - eflag_id = sys_event_flag.GetNewId(new event_flag(init, (u32)attr->protocol, (int)attr->type)); + 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", wxString(attr->name, 8).wx_str(), (u32)attr->protocol, (int)attr->type, eflag_id.GetValue()); @@ -47,9 +47,14 @@ int sys_event_flag_destroy(u32 eflag_id) { sys_event_flag.Warning("sys_event_flag_destroy(eflag_id=%d)", eflag_id); - event_flag* ef; + EventFlag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + if (ef->waiters.GetCount()) // ??? + { + return CELL_EBUSY; + } + Emu.GetIdManager().RemoveID(eflag_id); return CELL_OK; @@ -77,16 +82,50 @@ int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 default: return CELL_EINVAL; } - event_flag* ef; + EventFlag* 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; + SMutexLocker lock(ef->m_mutex); + if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.GetCount() > 0) + { + return CELL_EPERM; + } + EventFlagWaiter rec; + rec.bitptn = bitptn; + rec.mode = mode; + rec.tid = tid; + ef->waiters.AddCpy(rec); + + if (ef->check() == tid) + { + u64 flags = ef->flags; + + ef->waiters.RemoveAt(ef->waiters.GetCount() - 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.IsGood()) + { + result = flags; + return CELL_OK; + } + + if (!result.GetAddr()) + { + return CELL_OK; + } + return CELL_EFAULT; + } } u32 counter = 0; @@ -94,39 +133,61 @@ int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 while (true) { + if (ef->signal.GetOwner() == tid) { SMutexLocker lock(ef->m_mutex); + ef->signal.unlock(tid); + u64 flags = ef->flags; - if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) || - ((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn))) + for (u32 i = 0; i < ef->waiters.GetCount(); i++) { - ef->waiters.invalidate(tid); + if (ef->waiters[i].tid == tid) + { + ef->waiters.RemoveAt(i); - if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) - { - ef->flags &= ~bitptn; - } - else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) - { - ef->flags = 0; - } + 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; + if (result.IsGood()) + { + result = flags; + return CELL_OK; + } + + if (!result.GetAddr()) + { + return CELL_OK; + } + return CELL_EFAULT; } - return CELL_EFAULT; } + + return CELL_ECANCELED; } Sleep(1); if (counter++ > max_counter) { - ef->waiters.invalidate(tid); + SMutexLocker lock(ef->m_mutex); + + for (u32 i = 0; i < ef->waiters.GetCount(); i++) + { + if (ef->waiters[i].tid == tid) + { + ef->waiters.RemoveAt(i); + break; + } + } + return CELL_ETIMEDOUT; } if (Emu.IsStopped()) @@ -159,7 +220,7 @@ int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result) default: return CELL_EINVAL; } - event_flag* ef; + EventFlag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; SMutexLocker lock(ef->m_mutex); @@ -183,6 +244,11 @@ int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result) result = flags; return CELL_OK; } + + if (!result.GetAddr()) + { + return CELL_OK; + } return CELL_EFAULT; } @@ -193,11 +259,23 @@ int sys_event_flag_set(u32 eflag_id, u64 bitptn) { sys_event_flag.Warning("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn); - event_flag* ef; + EventFlag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - SMutexLocker lock(ef->m_mutex); + 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; } @@ -206,7 +284,7 @@ int sys_event_flag_clear(u32 eflag_id, u64 bitptn) { sys_event_flag.Warning("sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn); - event_flag* ef; + EventFlag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; SMutexLocker lock(ef->m_mutex); @@ -217,27 +295,61 @@ 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()); + sys_event_flag.Warning("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr()); - event_flag* ef; + EventFlag* ef; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - return CELL_OK; + Array tids; + + { + SMutexLocker lock(ef->m_mutex); + tids.SetCount(ef->waiters.GetCount()); + for (u32 i = 0; i < ef->waiters.GetCount(); i++) + { + tids[i] = ef->waiters[i].tid; + } + ef->waiters.Clear(); + } + + for (u32 i = 0; i < tids.GetCount(); i++) + { + if (Emu.IsStopped()) break; + ef->signal.lock(tids[i]); + } + + if (Emu.IsStopped()) + { + ConLog.Warning("sys_event_flag_cancel(id=%d) aborted", eflag_id); + return CELL_OK; + } + + if (num.IsGood()) + { + num = tids.GetCount(); + return CELL_OK; + } + + if (!num.GetAddr()) + { + return CELL_OK; + } + return CELL_EFAULT; } int sys_event_flag_get(u32 eflag_id, mem64_t flags) { sys_event_flag.Warning("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; + if (!flags.IsGood()) { return CELL_EFAULT; } - - event_flag* ef; - if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - flags = ef->flags; + flags = ef->flags; // ??? return CELL_OK; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h index 95d8391b00..97209f335a 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event_flag.h @@ -22,18 +22,54 @@ struct sys_event_flag_attr char name[8]; }; -struct event_flag +struct EventFlagWaiter +{ + u32 tid; + u32 mode; + u64 bitptn; +}; + +struct EventFlag { SMutex m_mutex; u64 flags; - SleepQueue waiters; + Array waiters; + SMutex signal; const u32 m_protocol; const int m_type; - event_flag(u64 pattern, u32 protocol, int 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.GetCount(); 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.AddCpy(waiters[i].tid); + } + } + + if (m_protocol == SYS_SYNC_PRIORITY) + { + target = sq.pop_prio(); + } + + return target; + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index 22f5d43018..ba890f681c 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -83,9 +83,12 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< return CELL_EFAULT; } - if(!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) + if (attr->name_addr) { - return CELL_EFAULT; + if(!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) + { + return CELL_EFAULT; + } } if(spu_num >= group_info->list.GetCount()) @@ -99,7 +102,13 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< } u32 spu_ep = (u32)img->entry_point; - std::string name = Memory.ReadString(attr->name_addr, attr->name_len).ToStdString(); + + std::string name = "SPUThread"; + if (attr->name_addr) + { + name = Memory.ReadString(attr->name_addr, attr->name_len).ToStdString(); + } + u64 a1 = arg->arg1; u64 a2 = arg->arg2; u64 a3 = arg->arg3; @@ -123,7 +132,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< (*(SPUThread*)&new_thread).group = group_info; sc_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d", - wxString(name).wx_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue()); + wxString(attr->name_addr ? name : "").wx_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue()); return CELL_OK; }