int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond) { sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); if (!lwcond.IsGood()) { return CELL_EFAULT; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) { return CELL_ESRCH; } mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); be_t<u32> tid = GetCurrentPPUThread().GetId(); if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) { if (mutex->mutex.owner.trylock(target) != SMR_OK) { mutex->mutex.owner.lock(tid); mutex->recursive_count = 1; mutex->mutex.owner.unlock(tid, target); } } if (Emu.IsStopped()) { ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue); } return CELL_OK; }
int sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout) { switch (int res = trylock(tid)) { case static_cast<int>(CELL_EBUSY): break; default: return res; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) { case se32(SYS_SYNC_PRIORITY): case se32(SYS_SYNC_FIFO): sq->push(tid); default: break; } switch (mutex.lock(tid, timeout)) { case SMR_OK: sq->invalidate(tid); case SMR_SIGNAL: recursive_count = 1; return CELL_OK; case SMR_TIMEOUT: sq->invalidate(tid); return CELL_ETIMEDOUT; case SMR_ABORT: if (Emu.IsStopped()) ConLog.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); default: sq->invalidate(tid); return CELL_EINVAL; } }
int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond) { sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr()); if (!lwcond.IsGood()) { return CELL_EFAULT; } u32 lwc = lwcond->lwcond_queue; SleepQueue* sq; if (!Emu.GetIdManager().GetIDData(lwc, sq)) { return CELL_ESRCH; } if (!sq->finalize()) { return CELL_EBUSY; } Emu.GetIdManager().RemoveID(lwc); return CELL_OK; }
int sys_lwmutex_t::unlock(be_t<u32> tid) { if (mutex.unlock(tid, tid) != SMR_OK) { return CELL_EPERM; } else { if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) { sc_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)recursive_count); recursive_count = 1; } recursive_count -= 1; if (!recursive_count.ToBE()) { be_t<u32> target = 0; switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) { case se32(SYS_SYNC_FIFO): case se32(SYS_SYNC_PRIORITY): SleepQueue* sq; if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; target = attribute & SYS_SYNC_FIFO ? sq->pop() : sq->pop_prio(); case se32(SYS_SYNC_RETRY): break; } if (target) mutex.unlock(tid, target); else mutex.unlock(tid); } return CELL_OK; } }
u32 EventFlag::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; }
int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout) { sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.GetAddr(), timeout); if (!lwcond.IsGood()) { return CELL_EFAULT; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) { return CELL_ESRCH; } mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); u32 tid_le = GetCurrentPPUThread().GetId(); be_t<u32> tid = tid_le; if (mutex->mutex.owner.GetOwner() != tid) { return CELL_EPERM; // caller must own this lwmutex } sq->push(tid_le); mutex->recursive_count = 0; mutex->mutex.owner.unlock(tid); u32 counter = 0; const u32 max_counter = timeout ? (timeout / 1000) : ~0; while (true) { /* switch (mutex->trylock(tid)) { case SMR_OK: mutex->unlock(tid); break; case SMR_SIGNAL: return CELL_OK; } */ if (mutex->mutex.owner.GetOwner() == tid) { _mm_mfence(); mutex->recursive_count = 1; return CELL_OK; } Sleep(1); if (counter++ > max_counter) { sq->invalidate(tid_le); return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue); return CELL_OK; } } }
int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id) { sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id); if (!lwcond.IsGood()) { return CELL_EFAULT; } SleepQueue* sq; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq)) { return CELL_ESRCH; } if (!sq->invalidate(ppu_thread_id)) { return CELL_EPERM; } mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex); be_t<u32> tid = GetCurrentPPUThread().GetId(); be_t<u32> target = ppu_thread_id; if (mutex->mutex.owner.trylock(target) != SMR_OK) { mutex->mutex.owner.lock(tid); mutex->recursive_count = 1; mutex->mutex.owner.unlock(tid, target); } if (Emu.IsStopped()) { ConLog.Warning("sys_lwcond_signal_to(sq=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id); } return CELL_OK; }
s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout) { sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); Lwcond* lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; } auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); u32 tid_le = GetCurrentPPUThread().GetId(); be_t<u32> tid = be_t<u32>::make(tid_le); SleepQueue* sq = nullptr; Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq); 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 } 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; if (sq) { mutex->mutex.unlock(tid, be_t<u32>::make(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); } u64 counter = 0; const u64 max_counter = timeout ? (timeout / 1000) : ~0; while (true) { if (lw->signal.unlock(tid, tid) == SMR_OK) { switch (mutex->lock(tid, 0)) { case CELL_OK: break; case static_cast<int>(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue); return CELL_OK; case static_cast<int>(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 static_cast<int>(CELL_EINVAL): goto abort; } mutex->recursive_count = 1; lw->signal.unlock(tid); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (counter++ > max_counter) { lw->m_queue.invalidate(tid_le); return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { goto abort; } } abort: sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); return CELL_OK; }