event flag improvement (not finished)

Fixed empty SPU thread name issue
This commit is contained in:
Nekotekina 2014-03-17 19:07:47 +04:00
parent 475c3ff967
commit c4d9223034
6 changed files with 267 additions and 53 deletions

View File

@ -896,9 +896,66 @@ public:
SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond(CELL_OK);
return; 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 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); // ??? SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return; return;
} }

View File

@ -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())) 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()) 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())) 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()) if (Emu.IsStopped())
{ {
@ -134,7 +134,7 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
u32 target = thread_id; u32 target = thread_id;
{ {
cond->cond.lock(target); cond->signal.lock(target);
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
@ -173,11 +173,11 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
while (true) while (true)
{ {
if (cond->cond.GetOwner() == tid) if (cond->signal.GetOwner() == tid)
{ {
mutex->m_mutex.lock(tid); mutex->m_mutex.lock(tid);
mutex->recursive = 1; mutex->recursive = 1;
cond->cond.unlock(tid); cond->signal.unlock(tid);
return CELL_OK; return CELL_OK;
} }

View File

@ -16,7 +16,7 @@ struct sys_cond_attribute
struct Cond struct Cond
{ {
Mutex* mutex; // associated with mutex Mutex* mutex; // associated with mutex
SMutex cond; SMutex signal;
SleepQueue m_queue; SleepQueue m_queue;
Cond(Mutex* mutex, u64 name) Cond(Mutex* mutex, u64 name)

View File

@ -6,7 +6,7 @@ SysCallBase sys_event_flag("sys_event_flag");
int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr, u64 init) int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> 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); eflag_id.GetAddr(), attr.GetAddr(), init);
if(!eflag_id.IsGood() || !attr.IsGood()) if(!eflag_id.IsGood() || !attr.IsGood())
@ -16,10 +16,10 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr,
switch (attr->protocol.ToBE()) 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_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_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; default: return CELL_EINVAL;
} }
@ -31,11 +31,11 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr,
switch (attr->type.ToBE()) switch (attr->type.ToBE())
{ {
case se32(SYS_SYNC_WAITER_SINGLE): 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; case se32(SYS_SYNC_WAITER_MULTIPLE): break;
default: return CELL_EINVAL; 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", 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()); 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); 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(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
if (ef->waiters.GetCount()) // ???
{
return CELL_EBUSY;
}
Emu.GetIdManager().RemoveID(eflag_id); Emu.GetIdManager().RemoveID(eflag_id);
return CELL_OK; 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; default: return CELL_EINVAL;
} }
event_flag* ef; EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
u32 tid = GetCurrentPPUThread().GetId(); 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); SMutexLocker lock(ef->m_mutex);
return CELL_EPERM; 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; 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) while (true)
{ {
if (ef->signal.GetOwner() == tid)
{ {
SMutexLocker lock(ef->m_mutex); SMutexLocker lock(ef->m_mutex);
ef->signal.unlock(tid);
u64 flags = ef->flags; u64 flags = ef->flags;
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) || for (u32 i = 0; i < ef->waiters.GetCount(); i++)
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn)))
{ {
ef->waiters.invalidate(tid); if (ef->waiters[i].tid == tid)
{
ef->waiters.RemoveAt(i);
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{ {
ef->flags &= ~bitptn; ef->flags &= ~bitptn;
} }
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{ {
ef->flags = 0; ef->flags = 0;
} }
if (result.IsGood()) if (result.IsGood())
{ {
result = flags; result = flags;
return CELL_OK; return CELL_OK;
}
if (!result.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT;
} }
return CELL_EFAULT;
} }
return CELL_ECANCELED;
} }
Sleep(1); Sleep(1);
if (counter++ > max_counter) 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; return CELL_ETIMEDOUT;
} }
if (Emu.IsStopped()) 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; default: return CELL_EINVAL;
} }
event_flag* ef; EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
SMutexLocker lock(ef->m_mutex); 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; result = flags;
return CELL_OK; return CELL_OK;
} }
if (!result.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT; 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); 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; 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; 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; 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); 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; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
SMutexLocker lock(ef->m_mutex); 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) 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; if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
return CELL_OK; Array<u32> 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) 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()); 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()) if (!flags.IsGood())
{ {
return CELL_EFAULT; 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; return CELL_OK;
} }

View File

@ -22,18 +22,54 @@ struct sys_event_flag_attr
char name[8]; char name[8];
}; };
struct event_flag struct EventFlagWaiter
{
u32 tid;
u32 mode;
u64 bitptn;
};
struct EventFlag
{ {
SMutex m_mutex; SMutex m_mutex;
u64 flags; u64 flags;
SleepQueue waiters; Array<EventFlagWaiter> waiters;
SMutex signal;
const u32 m_protocol; const u32 m_protocol;
const int m_type; const int m_type;
event_flag(u64 pattern, u32 protocol, int type) EventFlag(u64 pattern, u32 protocol, int type)
: flags(pattern) : flags(pattern)
, m_protocol(protocol) , m_protocol(protocol)
, m_type(type) , 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;
}
}; };

View File

@ -83,9 +83,12 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
return CELL_EFAULT; 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()) 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; 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 a1 = arg->arg1;
u64 a2 = arg->arg2; u64 a2 = arg->arg2;
u64 a3 = arg->arg3; 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; (*(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", 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; return CELL_OK;
} }