SC_Lwcond fixed

This commit is contained in:
Nekotekina 2014-03-23 01:04:55 +04:00
parent d0ea397492
commit be80a7c39c
4 changed files with 96 additions and 95 deletions

View file

@ -16,7 +16,7 @@ int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> l
} }
lwcond->lwmutex = lwmutex.GetAddr(); lwcond->lwmutex = lwmutex.GetAddr();
lwcond->lwcond_queue = sys_lwcond.GetNewId(new SleepQueue(attr->name_u64)); lwcond->lwcond_queue = sys_lwcond.GetNewId(new Lwcond(attr->name_u64));
if (lwmutex.IsGood()) if (lwmutex.IsGood())
{ {
@ -49,20 +49,20 @@ int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT; return CELL_EFAULT;
} }
u32 lwc = lwcond->lwcond_queue; u32 id = lwcond->lwcond_queue;
SleepQueue* sq; Lwcond* lw;
if (!Emu.GetIdManager().GetIDData(lwc, sq)) if (!Emu.GetIdManager().GetIDData(id, lw))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!sq->finalize()) if (!lw->m_queue.finalize())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
Emu.GetIdManager().RemoveID(lwc); Emu.GetIdManager().RemoveID(id);
return CELL_OK; return CELL_OK;
} }
@ -75,37 +75,23 @@ int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT; return CELL_EFAULT;
} }
SleepQueue* sq; Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid); if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop()))
if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
{ {
if (!was_locked) lw->signal.lock(target);
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue); ConLog.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}
} }
return CELL_OK; return CELL_OK;
@ -120,37 +106,23 @@ int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT; return CELL_EFAULT;
} }
SleepQueue* sq; Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid); while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop()))
while (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
{ {
if (!was_locked) lw->signal.lock(target);
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
ConLog.Warning("sys_lwcond_signal_all(sq=%d) aborted", (u32)lwcond->lwcond_queue); ConLog.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}
} }
return CELL_OK; return CELL_OK;
@ -165,8 +137,8 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_EFAULT; return CELL_EFAULT;
} }
SleepQueue* sq; Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -176,36 +148,20 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!sq->invalidate(ppu_thread_id)) if (!lw->m_queue.invalidate(ppu_thread_id))
{ {
return CELL_EPERM; return CELL_EPERM;
} }
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); u32 target = ppu_thread_id;
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid);
be_t<u32> target = ppu_thread_id;
{ {
if (!was_locked) lw->signal.lock(target);
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
ConLog.Warning("sys_lwcond_signal_to(sq=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id); ConLog.Warning("sys_lwcond_signal_to(id=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id);
return CELL_OK;
}
} }
return CELL_OK; return CELL_OK;
@ -220,8 +176,8 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
return CELL_EFAULT; return CELL_EFAULT;
} }
SleepQueue* sq; Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -230,29 +186,57 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
u32 tid_le = GetCurrentPPUThread().GetId(); u32 tid_le = GetCurrentPPUThread().GetId();
be_t<u32> tid = tid_le; be_t<u32> tid = tid_le;
SleepQueue* sq = nullptr;
Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq);
if (mutex->mutex.GetOwner() != tid) if (mutex->mutex.GetOwner() != tid)
{ {
sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue);
return CELL_EPERM; // caller must own this lwmutex return CELL_EPERM; // caller must own this lwmutex
} }
sq->push(tid_le); lw->m_queue.push(tid_le);
if (mutex->recursive_count.ToBE() != se32(1))
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had wrong recursive value (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->recursive_count);
}
mutex->recursive_count = 0; mutex->recursive_count = 0;
mutex->mutex.unlock(tid);
if (sq)
{
mutex->mutex.unlock(tid, mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop());
}
else if (mutex->attribute.ToBE() == se32(SYS_SYNC_RETRY))
{
mutex->mutex.unlock(tid); // SYS_SYNC_RETRY
}
else
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
}
u32 counter = 0; u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : ~0; const u32 max_counter = timeout ? (timeout / 1000) : ~0;
while (true) while (true)
{ {
/* switch (mutex->trylock(tid)) if (lw->signal.unlock(tid, tid) == SMR_OK)
{ {
case SMR_OK: mutex->unlock(tid); break; switch (mutex->lock(tid, 0))
case SMR_SIGNAL: return CELL_OK; {
} */ case CELL_OK: break;
if (mutex->mutex.GetOwner() == tid) case CELL_EDEADLK: sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked",
{ (u32)lwcond->lwcond_queue); return CELL_OK;
_mm_mfence(); case CELL_ESRCH: sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH;
case CELL_EINVAL: goto abort;
}
mutex->recursive_count = 1; mutex->recursive_count = 1;
lw->signal.unlock(tid);
return CELL_OK; return CELL_OK;
} }
@ -260,13 +244,16 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
if (counter++ > max_counter) if (counter++ > max_counter)
{ {
sq->invalidate(tid_le); lw->m_queue.invalidate(tid_le);
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue); goto abort;
return CELL_OK;
} }
} }
abort:
ConLog.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
} }

View file

@ -13,4 +13,15 @@ struct sys_lwcond_t
{ {
be_t<u32> lwmutex; be_t<u32> lwmutex;
be_t<u32> lwcond_queue; be_t<u32> lwcond_queue;
};
struct Lwcond
{
SMutex signal;
SleepQueue m_queue;
Lwcond(u64 name)
: m_queue(name)
{
}
}; };

View file

@ -206,10 +206,11 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
{ {
if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL;
be_t<u32> owner_tid = mutex.GetOwner(); be_t<u32> owner_tid = mutex.GetFreeValue();
if (owner_tid != mutex.GetFreeValue()) if (mutex.unlock(owner_tid, owner_tid) != SMR_OK) // check free value
{ {
owner_tid = mutex.GetOwner();
if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid)) if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid))
{ {
if (!tt->IsAlive()) if (!tt->IsAlive())
@ -263,7 +264,7 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
int sys_lwmutex_t::unlock(be_t<u32> tid) int sys_lwmutex_t::unlock(be_t<u32> tid)
{ {
if (tid != mutex.GetOwner()) if (mutex.unlock(tid, tid) != SMR_OK)
{ {
return CELL_EPERM; return CELL_EPERM;
} }

View file

@ -44,8 +44,10 @@ void sys_spinlock_unlock(mem_ptr_t<spinlock> lock)
{ {
sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.GetAddr()); sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.GetAddr());
again:
switch (lock->mutex.unlock(lock->mutex.GetOwner())) switch (lock->mutex.unlock(lock->mutex.GetOwner()))
{ {
case SMR_PERMITTED: goto again;
default: break; default: break;
} }
} }