diff --git a/Utilities/MTRingbuffer.h b/Utilities/MTRingbuffer.h index 991dbc077b..91b44d5a5b 100644 --- a/Utilities/MTRingbuffer.h +++ b/Utilities/MTRingbuffer.h @@ -30,7 +30,7 @@ public: { //wait until there's actually something to get //throwing an exception might be better, blocking here is a little awkward - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } size_t ret = mGet; mGet = moveGet(); @@ -45,7 +45,7 @@ public: { //if this is reached a lot it's time to increase the buffer size //or implement dynamic re-sizing - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } mBuffer[mPut] = std::forward(putEle); mPut = movePut(); @@ -94,7 +94,7 @@ public: { //if this is reached a lot it's time to increase the buffer size //or implement dynamic re-sizing - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (mPut + length <= mBuffer.size()) { diff --git a/Utilities/SMutex.cpp b/Utilities/SMutex.cpp deleted file mode 100644 index e10296bd68..0000000000 --- a/Utilities/SMutex.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" -#include "Emu/CPU/CPUThread.h" - -#include "Utilities/SMutex.h" - -bool SM_IsAborted() -{ - return Emu.IsStopped(); -} diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h deleted file mode 100644 index 5d50fe18e1..0000000000 --- a/Utilities/SMutex.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once -#include "Emu/Memory/atomic_type.h" - -bool SM_IsAborted(); - -enum SMutexResult -{ - SMR_OK = 0, // succeeded (lock, trylock, unlock) - SMR_FAILED, // failed (trylock, unlock) - SMR_DEADLOCK, // mutex reached deadlock (lock, trylock) - SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread - SMR_PERMITTED, // not owner of the mutex (unlock) - SMR_ABORT, // emulator has been stopped (lock, trylock, unlock) - SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock) - SMR_TIMEOUT, // timed out (lock) -}; - -template -< - typename T, - const u64 free_value = 0, - const u64 dead_value = 0xffffffffffffffffull -> -class SMutexBase -{ - static_assert(sizeof(T) == sizeof(atomic_le_t), "Invalid SMutexBase type"); - T owner; - typedef atomic_le_t AT; - -public: - static const T GetFreeValue() - { - static const u64 value = free_value; - return (T&)value; - } - - static const T GetDeadValue() - { - static const u64 value = dead_value; - return (T&)value; - } - - void initialize() - { - owner = GetFreeValue(); - } - - void finalize() - { - owner = GetDeadValue(); - } - - __forceinline T GetOwner() const - { - return (T&)owner; - } - - SMutexResult trylock(T tid) - { - if (SM_IsAborted()) - { - return SMR_ABORT; - } - T old = reinterpret_cast(owner).compare_and_swap(GetFreeValue(), tid); - - if (old != GetFreeValue()) - { - if (old == tid) - { - return SMR_DEADLOCK; - } - if (old == GetDeadValue()) - { - return SMR_DESTROYED; - } - return SMR_FAILED; - } - - return SMR_OK; - } - - SMutexResult unlock(T tid, T to = GetFreeValue()) - { - if (SM_IsAborted()) - { - return SMR_ABORT; - } - T old = reinterpret_cast(owner).compare_and_swap(tid, to); - - if (old != tid) - { - if (old == GetFreeValue()) - { - return SMR_FAILED; - } - if (old == GetDeadValue()) - { - return SMR_DESTROYED; - } - - return SMR_PERMITTED; - } - - return SMR_OK; - } - - SMutexResult lock(T tid, u64 timeout = 0) - { - u64 counter = 0; - - while (true) - { - switch (SMutexResult res = trylock(tid)) - { - case SMR_FAILED: break; - default: return res; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - if (timeout && counter++ > timeout) - { - return SMR_TIMEOUT; - } - } - } -}; - -typedef SMutexBase SMutex; diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index aa131b69a6..605618b9c6 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -38,7 +38,7 @@ public: return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -65,7 +65,7 @@ public: return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -100,7 +100,7 @@ public: return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 09334171dc..42e7c5d07c 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -160,10 +160,10 @@ public: // register waiter waiter_reg_t waiter(*this, signal_id); - // check condition or if emulator is stopped + // check the condition or if the emulator is stopped while (!waiter_func() && !is_stopped(signal_id)) { - // initialize waiter (only first time) + // initialize waiter (only once) waiter.init(); // wait for 1 ms or until signal arrived waiter.thread->WaitForAnySignal(1); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 5990228a29..b3986e970d 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -21,8 +21,6 @@ CPUThread::CPUThread(CPUThreadType type) , m_stack_addr(0) , m_offset(0) , m_prio(0) - , m_sync_wait(false) - , m_wait_thread_id(-1) , m_dec(nullptr) , m_is_step(false) , m_is_branch(false) @@ -44,7 +42,7 @@ bool CPUThread::IsStopped() const { return m_status == Stopped; } void CPUThread::Close() { - ThreadBase::Stop(m_sync_wait); + ThreadBase::Stop(false); DoStop(); delete m_dec; @@ -55,9 +53,6 @@ void CPUThread::Reset() { CloseStack(); - m_sync_wait = 0; - m_wait_thread_id = -1; - SetPc(0); cycle = 0; m_is_branch = false; @@ -89,24 +84,6 @@ void CPUThread::SetName(const std::string& name) NamedThreadBase::SetThreadName(name); } -void CPUThread::Wait(bool wait) -{ - std::lock_guard lock(m_cs_sync); - m_sync_wait = wait; -} - -void CPUThread::Wait(const CPUThread& thr) -{ - std::lock_guard lock(m_cs_sync); - m_wait_thread_id = thr.GetId(); - m_sync_wait = true; -} - -bool CPUThread::Sync() -{ - return m_sync_wait; -} - int CPUThread::ThreadStatus() { if(Emu.IsStopped() || IsStopped() || IsPaused()) @@ -124,7 +101,7 @@ int CPUThread::ThreadStatus() return CPUThread_Step; } - if (Emu.IsPaused() || Sync()) + if (Emu.IsPaused()) { return CPUThread_Sleeping; } @@ -334,7 +311,7 @@ void CPUThread::Task() if (status == CPUThread_Sleeping) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 6bfbc0e8d4..6b1471705b 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -136,23 +136,6 @@ protected: public: virtual ~CPUThread(); - u32 m_wait_thread_id; - - std::mutex m_cs_sync; - bool m_sync_wait; - void Wait(bool wait); - void Wait(const CPUThread& thr); - bool Sync(); - - template - void WaitFor(T func) - { - while(func(ThreadStatus())) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - int ThreadStatus(); void NextPc(u8 instr_size); @@ -280,7 +263,7 @@ public: thread->SetJoinable(false); while (thread->IsRunning()) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return thread->GetExitStatus(); } diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index b745da0177..2ddeac6406 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -72,12 +72,6 @@ void CPUThreadManager::RemoveThread(const u32 id) for (u32 i = 0; i < m_threads.size(); ++i) { - if (m_threads[i]->m_wait_thread_id == id) - { - m_threads[i]->Wait(false); - m_threads[i]->m_wait_thread_id = -1; - } - if (m_threads[i]->GetId() != id) continue; thr = m_threads[i]; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index f82a84f683..778b42c621 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -3,12 +3,13 @@ #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include "Emu/Memory/atomic_type.h" +#include "Utilities/SQueue.h" #include "Emu/IdManager.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" #include "Emu/SysCalls/ErrorCodes.h" -#include "Utilities/SMutex.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_event_flag.h" #include "Emu/SysCalls/lv2/sys_time.h" @@ -588,7 +589,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); while (!SPU.Out_IntrMBox.Push(v)) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); @@ -721,21 +722,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) return; } - const u32 tid = GetId(); + std::lock_guard lock(ef->mutex); - 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); + ef->signal.Push(target, nullptr); } - else - { - ef->m_mutex.unlock(tid); - } - SPU.In_MBox.PushUncond(CELL_OK); return; } @@ -769,21 +762,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) return; } - const u32 tid = GetId(); + std::lock_guard lock(ef->mutex); - 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); + ef->signal.Push(target, nullptr); } - else - { - ef->m_mutex.unlock(tid); - } - return; } else @@ -806,7 +791,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) case SPU_WrOutMbox: { - while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -917,13 +905,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { case SPU_RdInMbox: { - while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } case MFC_RdTagStat: { - while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -937,11 +931,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { if (cfg.value & 1) { - while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } else { - while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } break; } @@ -950,24 +950,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { if (cfg.value & 2) { - while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } else { - while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } break; } case MFC_RdAtomicStat: { - while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } case MFC_RdListStallStat: { - while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!StallStat.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -985,7 +997,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch) case SPU_RdEventStat: { - while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!CheckEvents() && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } v = m_events & m_event_mask; break; } @@ -1067,43 +1082,51 @@ void SPUThread::StopAndSignal(u32 code) u32 tid = GetId(); - eq->sq.push(tid); // add thread to sleep queue + eq->sq.push(tid, eq->protocol); // add thread to sleep queue while (true) { - switch (eq->owner.trylock(tid)) + u32 old_owner = eq->owner.compare_and_swap(0, tid); + + switch (s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0) { - case SMR_OK: - if (!eq->events.count()) + case 0: + { + const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0; + if (next != tid) { - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, next)) + { + assert(!"sys_spu_thread_receive_event() failed (I)"); + } break; } - else - { - u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); - if (next != tid) - { - eq->owner.unlock(tid, next); - break; - } - } - case SMR_SIGNAL: + // fallthrough + } + case 1: { sys_event_data event; eq->events.pop(event); - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, 0)) + { + assert(!"sys_spu_thread_receive_event() failed (II)"); + } SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond((u32)event.data1); SPU.In_MBox.PushUncond((u32)event.data2); SPU.In_MBox.PushUncond((u32)event.data3); return; } - case SMR_FAILED: break; - default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (!~old_owner) + { + eq->sq.invalidate(tid); + SPU.In_MBox.PushUncond(CELL_ECANCELED); + return; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index b64573e17f..ff37e9660c 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -1,8 +1,7 @@ #pragma once -#include "Utilities/SMutex.h" #include "Emu/Memory/atomic_type.h" #include "PPCThread.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Event.h" #include "MFC.h" diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp index b8485942b9..b3cdb2931f 100644 --- a/rpcs3/Emu/Event.cpp +++ b/rpcs3/Emu/Event.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Event.h" diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 311dd3143c..0ec87d8cad 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2215,7 +2215,7 @@ void RSXThread::Task() continue; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } is_vblank_stopped = true; @@ -2246,7 +2246,7 @@ void RSXThread::Task() m_sem_flush.post_and_wait(); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -2332,7 +2332,7 @@ void RSXThread::Task() while (!is_vblank_stopped) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } LOG_NOTICE(RSX, "RSX thread ended"); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 8cabbae3b4..c6fecc11ba 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -244,12 +244,6 @@ u32 adecOpen(AudioDecoder* data) break; } - //if (!adec.job.GetCountUnsafe() && adec.is_running) - //{ - // std::this_thread::sleep_for(std::chrono::milliseconds(1)); - // continue; - //} - if (!adec.job.Pop(task, &adec.is_closed)) { break; @@ -576,7 +570,7 @@ int cellAdecClose(u32 handle) cellAdec->Warning("cellAdecClose(%d) aborted", handle); break; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId()); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 7ace6e1414..0e5bdc7e27 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -6,9 +6,8 @@ #include "rpcs3/Ini.h" #include "Utilities/SQueue.h" -#include "Utilities/SMutex.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_time.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Event.h" #include "Emu/Audio/AudioManager.h" @@ -461,7 +460,7 @@ abort: while (!internal_finished) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } m_config.m_is_audio_finalized = true; @@ -475,7 +474,7 @@ abort: cellAudio->Warning("cellAudioInit() aborted"); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } return CELL_OK; @@ -494,7 +493,7 @@ int cellAudioQuit() while (!m_config.m_is_audio_finalized) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { cellAudio->Warning("cellAudioQuit(): aborted"); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 96e7eddaa9..7c340a8950 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -288,9 +288,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr attr) { if (esFilterId->filterIdMajor >= 0xe0) - attr->memSize = 0x500000; // 0x45fa49 from ps3 + attr->memSize = 0x400000; // 0x45fa49 from ps3 else - attr->memSize = 0x8000; // 0x73d9 from ps3 + attr->memSize = 0x6000; // 0x73d9 from ps3 cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); @@ -454,7 +454,7 @@ u32 dmuxOpen(Demuxer* data) if (es.raw_data.size() > 1024 * 1024) { stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -550,7 +550,7 @@ u32 dmuxOpen(Demuxer* data) if (es.isfull(old_size)) { stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -714,7 +714,7 @@ u32 dmuxOpen(Demuxer* data) { if (Emu.IsStopped() || dmux.is_closed) break; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); @@ -868,7 +868,7 @@ int cellDmuxClose(u32 demuxerHandle) return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId()); @@ -936,7 +936,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index 1f0e1d7feb..f6f7fefbbe 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -156,7 +156,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptrWarning("MsgDialog thread aborted"); return; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0) @@ -166,7 +166,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptrm.flags1 & SF1_EXIT_IF_NO_WORK) { - if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) + if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0)) { assert(!"sys_lwmutex_lock() failed"); } if (spurs->m.xD66.read_relaxed()) { - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -620,7 +622,7 @@ s64 spursInit( spurs->m.xD65.exchange(1); if (spurs->m.xD64.read_relaxed() == 0) { - if (s32 res = sys_lwcond_wait(spurs->get_lwcond(), 0)) + if (s32 res = sys_lwcond_wait(CPU, spurs->get_lwcond(), 0)) { assert(!"sys_lwcond_wait() failed"); } @@ -628,7 +630,7 @@ s64 spursInit( spurs->m.xD65.exchange(0); if (spurs->m.xD66.read_relaxed()) { - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -638,7 +640,7 @@ s64 spursInit( if (Emu.IsStopped()) continue; - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -705,7 +707,7 @@ s64 spursInit( } else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup { - return spursWakeUp(spurs); + return spursWakeUp(GetCurrentPPUThread(), spurs); } return CELL_OK; @@ -1265,7 +1267,7 @@ s64 cellSpursGetInfo(vm::ptr spurs, vm::ptr info) #endif } -s64 spursWakeUp(vm::ptr spurs) +s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs) { #ifdef PRX_DEBUG_XXX return cb_call>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs); @@ -1287,7 +1289,7 @@ s64 spursWakeUp(vm::ptr spurs) spurs->m.xD64.exchange(1); if (spurs->m.xD65.read_sync()) { - if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) + if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0)) { assert(!"sys_lwmutex_lock() failed"); } @@ -1295,7 +1297,7 @@ s64 spursWakeUp(vm::ptr spurs) { assert(!"sys_lwcond_signal() failed"); } - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -1303,11 +1305,11 @@ s64 spursWakeUp(vm::ptr spurs) return CELL_OK; } -s64 cellSpursWakeUp(vm::ptr spurs) +s64 cellSpursWakeUp(PPUThread& CPU, vm::ptr spurs) { cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr()); - return spursWakeUp(spurs); + return spursWakeUp(CPU, spurs); } s32 spursAddWorkload( diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index d546474c1a..05ffbad6c4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -604,5 +604,7 @@ struct CellSpursTaskBinInfo CellSpursTaskLsPattern lsPattern; }; +class PPUThread; + s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool wasCreated); -s64 spursWakeUp(vm::ptr spurs); +s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp index e1094c6cd9..6739c5b34e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp @@ -3,8 +3,9 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_spu.h" diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 6534688cbd..fca2ca40f7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -4,9 +4,8 @@ #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/Event.h" diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 95f9285f86..3474b9bde8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -234,12 +234,6 @@ u32 vdecOpen(VideoDecoder* data) break; } - //if (!vdec.job.GetCountUnsafe() && vdec.is_running) - //{ - // std::this_thread::sleep_for(std::chrono::milliseconds(1)); - // continue; - //} - if (!vdec.job.Pop(task, &vdec.is_closed)) { break; @@ -612,7 +606,7 @@ int cellVdecClose(u32 handle) cellVdec->Warning("cellVdecClose(%d) aborted", handle); break; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId()); diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index bd7527c5cf..21646f4d1c 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -347,7 +347,7 @@ int cellSurMixerCreate(vm::ptr config) if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index ff2e042147..a21eb18ab2 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -4,9 +4,10 @@ #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" #include "Emu/FS/vfsFile.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_spinlock.h" diff --git a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp index 46e255925d..82a019a886 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp @@ -155,7 +155,7 @@ void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptrWarning("fsAioRead() aborted"); diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index bf4e2ebc31..1a97b2290e 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -6,9 +6,10 @@ #include "Emu/System.h" #include "ModuleManager.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" #include "lv2/lv2Fs.h" +#include "lv2/sleep_queue_type.h" #include "lv2/sys_lwmutex.h" #include "lv2/sys_mutex.h" #include "lv2/sys_cond.h" @@ -139,11 +140,11 @@ static func_caller* sc_table[kSyscallTableLength] = bind_func(sys_semaphore_wait), //92 (0x05C) bind_func(sys_semaphore_trywait), //93 (0x05D) bind_func(sys_semaphore_post), //94 (0x05E) - null_func,//bind_func(sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create - null_func,//bind_func(sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy - null_func,//bind_func(sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock - null_func,//bind_func(sys_lwmutex_trylock), //98 (0x062) // internal, used by sys_lwmutex_unlock - null_func,//bind_func(sys_lwmutex_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock + null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create + null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy + null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock + null_func,//bind_func(_sys_lwmutex_trylock), //98 (0x062) // internal, used by sys_lwmutex_unlock + null_func,//bind_func(_sys_lwmutex_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock bind_func(sys_mutex_create), //100 (0x064) bind_func(sys_mutex_destroy), //101 (0x065) bind_func(sys_mutex_lock), //102 (0x066) @@ -155,9 +156,9 @@ static func_caller* sc_table[kSyscallTableLength] = bind_func(sys_cond_signal), //108 (0x06C) bind_func(sys_cond_signal_all), //109 (0x06D) bind_func(sys_cond_signal_to), //110 (0x06E) - null_func,//bind_func(sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create - null_func,//bind_func(sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy - null_func,//bind_func(sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait + null_func,//bind_func(_sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create + null_func,//bind_func(_sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy + null_func,//bind_func(_sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait bind_func(sys_semaphore_get_value), //114 (0x072) null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp new file mode 100644 index 0000000000..d4c820f68e --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp @@ -0,0 +1,149 @@ +#include "stdafx.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/Memory/atomic_type.h" + +#include "Emu/CPU/CPUThreadManager.h" +#include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" + +void sleep_queue_t::push(u32 tid, u32 protocol) +{ + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + list.push_back(tid); + return; + } + case SYS_SYNC_RETRY: + { + return; + } + } + + LOG_ERROR(HLE, "sleep_queue_t::push(): unsupported protocol (0x%x)", protocol); + Emu.Pause(); +} + +u32 sleep_queue_t::pop(u32 protocol) +{ + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + { + std::lock_guard lock(m_mutex); + + while (true) + { + if (list.size()) + { + u32 res = list[0]; + list.erase(list.begin()); + if (res && Emu.GetIdManager().CheckID(res)) + // check thread + { + return res; + } + } + return 0; + } + } + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + while (true) + { + if (list.size()) + { + u64 highest_prio = ~0ull; + u32 sel = 0; + for (u32 i = 0; i < list.size(); i++) + { + CPUThread* t = Emu.GetCPU().GetThread(list[i]); + if (!t) + { + list[i] = 0; + sel = i; + break; + } + u64 prio = t->GetPrio(); + if (prio < highest_prio) + { + highest_prio = prio; + sel = i; + } + } + u32 res = list[sel]; + list.erase(list.begin() + sel); + /* if (Emu.GetIdManager().CheckID(res)) */ + if (res) + // check thread + { + return res; + } + } + + return 0; + } + } + case SYS_SYNC_RETRY: + { + return 0; + } + } + + LOG_ERROR(HLE, "sleep_queue_t::pop(): unsupported protocol (0x%x)", protocol); + Emu.Pause(); + return 0; +} + +bool sleep_queue_t::invalidate(u32 tid) +{ + std::lock_guard lock(m_mutex); + + if (tid) for (u32 i = 0; i < list.size(); i++) + { + if (list[i] == tid) + { + list.erase(list.begin() + i); + return true; + } + } + + return false; +} + +u32 sleep_queue_t::count() +{ + std::lock_guard lock(m_mutex); + + u32 result = 0; + for (u32 i = 0; i < list.size(); i++) + { + if (list[i]) result++; + } + return result; +} + +bool sleep_queue_t::finalize() +{ + if (!m_mutex.try_lock()) return false; + + for (u32 i = 0; i < list.size(); i++) + { + if (list[i]) + { + m_mutex.unlock(); + return false; + } + } + + m_mutex.unlock(); + return true; +} diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h new file mode 100644 index 0000000000..4782b56671 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h @@ -0,0 +1,45 @@ +#pragma once + +// attr_protocol (waiting scheduling policy) +enum +{ + // First In, First Out + SYS_SYNC_FIFO = 1, + // Priority Order + SYS_SYNC_PRIORITY = 2, + // Basic Priority Inheritance Protocol (probably not implemented) + SYS_SYNC_PRIORITY_INHERIT = 3, + // Not selected while unlocking + SYS_SYNC_RETRY = 4, + // + SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, +}; + +// attr_recursive (recursive locks policy) +enum +{ + // Recursive locks are allowed + SYS_SYNC_RECURSIVE = 0x10, + // Recursive locks are NOT allowed + SYS_SYNC_NOT_RECURSIVE = 0x20, + // + SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? +}; + +struct sleep_queue_t +{ + std::vector list; + std::mutex m_mutex; + u64 m_name; + + sleep_queue_t(u64 name = 0) + : m_name(name) + { + } + + void push(u32 tid, u32 protocol); + u32 pop(u32 protocol); + bool invalidate(u32 tid); + u32 count(); + bool finalize(); +}; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index c6c71ed9a9..d1416c7b9c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -3,11 +3,12 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_mutex.h" #include "sys_cond.h" @@ -33,7 +34,7 @@ s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptrname_u64); - u32 id = sys_cond.GetNewId(cond, TYPE_COND); + const u32 id = sys_cond.GetNewId(cond, TYPE_COND); *cond_id = id; mutex->cond_count++; sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id); @@ -54,7 +55,7 @@ s32 sys_cond_destroy(u32 cond_id) return CELL_ESRCH; } - if (!cond->m_queue.finalize()) + if (!cond->queue.finalize()) { return CELL_EBUSY; } @@ -77,9 +78,9 @@ s32 sys_cond_signal(u32 cond_id) Mutex* mutex = cond->mutex; - if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) + if (u32 target = cond->queue.pop(mutex->protocol)) { - cond->signal.lock(target); + cond->signal.Push(target, nullptr); if (Emu.IsStopped()) { @@ -102,10 +103,9 @@ s32 sys_cond_signal_all(u32 cond_id) Mutex* mutex = cond->mutex; - while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) + while (u32 target = cond->queue.pop(mutex->protocol)) { - cond->signaler = GetCurrentPPUThread().GetId(); - cond->signal.lock(target); + cond->signal.Push(target, nullptr); if (Emu.IsStopped()) { @@ -114,7 +114,6 @@ s32 sys_cond_signal_all(u32 cond_id) } } - cond->signaler = 0; return CELL_OK; } @@ -133,7 +132,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_ESRCH; } - if (!cond->m_queue.invalidate(thread_id)) + if (!cond->queue.invalidate(thread_id)) { return CELL_EPERM; } @@ -142,7 +141,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) u32 target = thread_id; { - cond->signal.lock(target); + cond->signal.Push(target, nullptr); } if (Emu.IsStopped()) @@ -153,7 +152,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_OK; } -s32 sys_cond_wait(u32 cond_id, u64 timeout) +s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) { sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout); @@ -164,65 +163,69 @@ s32 sys_cond_wait(u32 cond_id, u64 timeout) } Mutex* mutex = cond->mutex; - u32 tid = GetCurrentPPUThread().GetId(); - if (mutex->m_mutex.GetOwner() != tid) + const u32 tid = CPU.GetId(); + if (mutex->owner.read_sync() != tid) { - sys_cond.Warning("sys_cond_wait(cond_id=%d) failed (EPERM)", cond_id); return CELL_EPERM; } - cond->m_queue.push(tid); + cond->queue.push(tid, mutex->protocol); auto old_recursive = mutex->recursive; mutex->recursive = 0; - mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); - - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : ~0ull; + if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol))) + { + assert(!"sys_cond_wait() failed"); + } + bool pushed_in_sleep_queue = false; + const u64 time_start = get_system_time(); while (true) { - if (cond->signal.unlock(tid, tid) == SMR_OK) + u32 signaled; + if (cond->signal.Peek(signaled, &sq_no_wait) && signaled == tid) // check signaled threads { - if (SMutexResult res = mutex->m_mutex.trylock(tid)) + if (mutex->owner.compare_and_swap_test(0, tid)) // try to lock { - if (res != SMR_FAILED) - { - goto abort; - } - mutex->m_queue.push(tid); - - switch (mutex->m_mutex.lock(tid)) - { - case SMR_OK: - mutex->m_queue.invalidate(tid); - case SMR_SIGNAL: - break; - default: - goto abort; - } + break; + } + + if (!pushed_in_sleep_queue) + { + mutex->queue.push(tid, mutex->protocol); + pushed_in_sleep_queue = true; + } + + auto old_owner = mutex->owner.compare_and_swap(0, tid); + if (!old_owner) + { + mutex->queue.invalidate(tid); + break; + } + if (old_owner == tid) + { + break; } - mutex->recursive = old_recursive; - cond->signal.unlock(tid); - return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (counter++ > max_counter) + if (timeout && get_system_time() - time_start > timeout) { - cond->m_queue.invalidate(tid); - GetCurrentPPUThread().owned_mutexes--; // ??? - return CELL_ETIMEDOUT; + cond->queue.invalidate(tid); + CPU.owned_mutexes--; // ??? + return CELL_ETIMEDOUT; // mutex not locked } + if (Emu.IsStopped()) { - goto abort; + sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id); + return CELL_OK; } } -abort: - sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id); + mutex->recursive = old_recursive; + cond->signal.Pop(cond_id /* unused result */, nullptr); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index faed699815..69e2faf27f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -15,25 +15,22 @@ struct sys_cond_attribute struct Cond { Mutex* mutex; // associated with mutex - SMutex signal; - u32 signaler; // signaler thread id (for signal_all) - SleepQueue m_queue; - - u64 signal_stamp; + SQueue signal; + sleep_queue_t queue; Cond(Mutex* mutex, u64 name) : mutex(mutex) - , m_queue(name) - , signaler(0) + , queue(name) { - signal.initialize(); } }; +class PPUThread; + // SysCalls s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr); s32 sys_cond_destroy(u32 cond_id); -s32 sys_cond_wait(u32 cond_id, u64 timeout); +s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout); s32 sys_cond_signal(u32 cond_id); s32 sys_cond_signal_all(u32 cond_id); s32 sys_cond_signal_to(u32 cond_id, u32 thread_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index 69d2add6f7..ae05dd4de3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -3,11 +3,10 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Event.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" #include "sys_process.h" #include "sys_event.h" @@ -88,19 +87,19 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode) u32 tid = GetCurrentPPUThread().GetId(); eq->sq.m_mutex.lock(); - eq->owner.lock(tid); + //eq->owner.lock(tid); // check if some threads are waiting for an event if (!mode && eq->sq.list.size()) { - eq->owner.unlock(tid); + //eq->owner.unlock(tid); eq->sq.m_mutex.unlock(); return CELL_EBUSY; } - eq->owner.unlock(tid, ~0); + //eq->owner.unlock(tid, ~0); eq->sq.m_mutex.unlock(); while (eq->sq.list.size()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id); @@ -140,16 +139,16 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_arra u32 tid = GetCurrentPPUThread().GetId(); eq->sq.m_mutex.lock(); - eq->owner.lock(tid); + //eq->owner.lock(tid); if (eq->sq.list.size()) { *number = 0; - eq->owner.unlock(tid); + //eq->owner.unlock(tid); eq->sq.m_mutex.unlock(); return CELL_OK; } *number = eq->events.pop_all(event_array.get_ptr(), size); - eq->owner.unlock(tid); + //eq->owner.unlock(tid); eq->sq.m_mutex.unlock(); return CELL_OK; } @@ -173,34 +172,38 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, u32 tid = GetCurrentPPUThread().GetId(); - eq->sq.push(tid); // add thread to sleep queue + eq->sq.push(tid, eq->protocol); // add thread to sleep queue timeout = timeout ? (timeout / 1000) : ~0; u64 counter = 0; while (true) { - switch (eq->owner.trylock(tid)) + u32 old_owner = eq->owner.compare_and_swap(0, tid); + const s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0; + + switch (res) { - case SMR_OK: - if (!eq->events.count()) + case 0: + { + const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0; + if (next != tid) { - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, next)) + { + assert(!"sys_event_queue_receive() failed (I)"); + } break; } - else - { - u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); - if (next != tid) - { - eq->owner.unlock(tid, next); - break; - } - } - case SMR_SIGNAL: + // fallthrough + } + case 1: { sys_event_data event; eq->events.pop(event); - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, 0)) + { + assert(!"sys_event_queue_receive() failed (II)"); + } sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", (u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3); /* passing event data in registers */ @@ -211,11 +214,15 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, t.GPR[7] = event.data3; return CELL_OK; } - case SMR_FAILED: break; - default: eq->sq.invalidate(tid); return CELL_ECANCELED; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (!~old_owner) + { + eq->sq.invalidate(tid); + return CELL_ECANCELED; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (counter++ > timeout || Emu.IsStopped()) { if (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/SysCalls/lv2/sys_event.h index 2dac0184b9..0d96819520 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.h @@ -1,8 +1,5 @@ #pragma once -//#include "sys_lwmutex.h" -//#include "Utilities/SMutex.h" - #define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL) // arbitrary code to prevent "special" zero value in key argument @@ -192,10 +189,10 @@ public: struct EventQueue { - SleepQueue sq; + sleep_queue_t sq; EventPortList ports; EventRingBuffer events; - SMutex owner; + atomic_le_t owner; const union { @@ -213,7 +210,7 @@ struct EventQueue , key(key) , events(size) // size: max event count this queue can hold { - owner.initialize(); + owner.write_relaxed(0); } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp index 80fe3c0738..909e31aa7b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -3,26 +3,27 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" #include "sys_event_flag.h" SysCallBase sys_event_flag("sys_event_flag"); u32 EventFlag::check() { - SleepQueue sq; // TODO: implement without SleepQueue + sleep_queue_t sq; // TODO: implement without sleep queue u32 target = 0; + const u64 flag_set = flags.read_sync(); 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 (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & waiters[i].bitptn) == waiters[i].bitptn) || + ((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & waiters[i].bitptn))) { - if (m_protocol == SYS_SYNC_FIFO) + if (protocol == SYS_SYNC_FIFO) { target = waiters[i].tid; break; @@ -31,8 +32,8 @@ u32 EventFlag::check() } } - if (m_protocol == SYS_SYNC_PRIORITY) - target = sq.pop_prio(); + if (protocol == SYS_SYNC_PRIORITY) + target = sq.pop(SYS_SYNC_PRIORITY); return target; } @@ -126,12 +127,13 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, const u32 tid = GetCurrentPPUThread().GetId(); { - ef->m_mutex.lock(tid); - if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0) + std::lock_guard lock(ef->mutex); + + if (ef->type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0) { - ef->m_mutex.unlock(tid); return CELL_EPERM; } + EventFlagWaiter rec; rec.bitptn = bitptn; rec.mode = mode; @@ -140,7 +142,7 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, if (ef->check() == tid) { - u64 flags = ef->flags; + const u64 flag_set = ef->flags.read_sync(); ef->waiters.erase(ef->waiters.end() - 1); @@ -150,15 +152,15 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } - if (result) *result = flags; - - ef->m_mutex.unlock(tid); + if (result) + { + *result = flag_set; + } return CELL_OK; } - ef->m_mutex.unlock(tid); } u64 counter = 0; @@ -166,10 +168,14 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, while (true) { - if (ef->signal.unlock(tid, tid) == SMR_OK) + u32 signaled; + if (ef->signal.Peek(signaled, &sq_no_wait) && signaled == tid) { - ef->m_mutex.lock(tid); - u64 flags = ef->flags; + std::lock_guard lock(ef->mutex); + + const u64 flag_set = ef->flags.read_sync(); + + ef->signal.Pop(signaled, nullptr); for (u32 i = 0; i < ef->waiters.size(); i++) { @@ -183,37 +189,30 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } if (u32 target = ef->check()) { - // if signal, leave both mutexes locked... - ef->signal.unlock(tid, target); - ef->m_mutex.unlock(tid, target); + ef->signal.Push(target, nullptr); } - else + + if (result) { - ef->signal.unlock(tid); + *result = flag_set; } - - if (result) *result = flags; - - ef->m_mutex.unlock(tid); return CELL_OK; } } - ef->signal.unlock(tid); - ef->m_mutex.unlock(tid); return CELL_ECANCELED; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (counter++ > max_counter) { - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); for (u32 i = 0; i < ef->waiters.size(); i++) { @@ -223,10 +222,9 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, break; } } - - ef->m_mutex.unlock(tid); return CELL_ETIMEDOUT; } + if (Emu.IsStopped()) { sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id); @@ -259,14 +257,13 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr resu EventFlag* ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + std::lock_guard lock(ef->mutex); - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); + const u64 flag_set = ef->flags.read_sync(); - 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_AND) && (flag_set & bitptn) == bitptn) || + ((mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & bitptn))) { if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) { @@ -274,16 +271,17 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr resu } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } - if (result) *result = flags; + if (result) + { + *result = flag_set; + } - ef->m_mutex.unlock(tid); return CELL_OK; } - ef->m_mutex.unlock(tid); return CELL_EBUSY; } @@ -294,21 +292,13 @@ s32 sys_event_flag_set(u32 eflag_id, u64 bitptn) EventFlag* ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - u32 tid = GetCurrentPPUThread().GetId(); + std::lock_guard lock(ef->mutex); - 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); + ef->signal.Push(target, nullptr); } - else - { - ef->m_mutex.unlock(tid); - } - return CELL_OK; } @@ -319,10 +309,8 @@ s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn) EventFlag* ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); ef->flags &= bitptn; - ef->m_mutex.unlock(tid); return CELL_OK; } @@ -334,23 +322,20 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr num) if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; std::vector tids; - - const u32 tid = GetCurrentPPUThread().GetId(); - { - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); + tids.resize(ef->waiters.size()); for (u32 i = 0; i < ef->waiters.size(); i++) { tids[i] = ef->waiters[i].tid; } ef->waiters.clear(); - ef->m_mutex.unlock(tid); } for (u32 i = 0; i < tids.size(); i++) { - ef->signal.lock(tids[i]); + ef->signal.Push(tids[i], nullptr); } if (Emu.IsStopped()) @@ -359,7 +344,10 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr num) return CELL_OK; } - if (num) *num = (u32)tids.size(); + if (num) + { + *num = (u32)tids.size(); + } return CELL_OK; } @@ -377,9 +365,6 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr flags) EventFlag* ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); - *flags = ef->flags; - ef->m_mutex.unlock(tid); + *flags = ef->flags.read_sync(); return CELL_OK; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h index 51f4fcb03e..277a4c59a8 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -31,20 +31,18 @@ struct EventFlagWaiter struct EventFlag { - SMutex m_mutex; - u64 flags; + atomic_le_t flags; + SQueue signal; + std::mutex mutex; // protects waiters std::vector waiters; - SMutex signal; - const u32 m_protocol; - const int m_type; + const u32 protocol; + const int type; EventFlag(u64 pattern, u32 protocol, int type) - : flags(pattern) - , m_protocol(protocol) - , m_type(type) + : protocol(protocol) + , type(type) { - m_mutex.initialize(); - signal.initialize(); + flags.write_relaxed(pattern); } u32 check(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 0cd6b28401..ff6e7ebf5a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -3,9 +3,11 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" +#include "Utilities/SQueue.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" @@ -52,7 +54,7 @@ s32 sys_lwcond_destroy(vm::ptr lwcond) return CELL_ESRCH; } - if (!lw->m_queue.finalize()) + if (!lw->queue.finalize()) { return CELL_EBUSY; } @@ -74,9 +76,9 @@ s32 sys_lwcond_signal(vm::ptr lwcond) auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) + if (u32 target = lw->queue.pop(mutex->attribute)) { - lw->signal.lock(target); + lw->signal.Push(target, nullptr); if (Emu.IsStopped()) { @@ -100,9 +102,9 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) + while (u32 target = lw->queue.pop(mutex->attribute)) { - lw->signal.lock(target); + lw->signal.Push(target, nullptr); if (Emu.IsStopped()) { @@ -129,14 +131,14 @@ s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id) return CELL_ESRCH; } - if (!lw->m_queue.invalidate(ppu_thread_id)) + if (!lw->queue.invalidate(ppu_thread_id)) { return CELL_EPERM; } u32 target = ppu_thread_id; { - lw->signal.lock(target); + lw->signal.Push(target, nullptr); if (Emu.IsStopped()) { @@ -148,7 +150,7 @@ s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id) return CELL_OK; } -s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout) +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) { sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); @@ -159,10 +161,10 @@ s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout) } auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - u32 tid_le = GetCurrentPPUThread().GetId(); + u32 tid_le = CPU.GetId(); be_t tid = be_t::make(tid_le); - SleepQueue* sq = nullptr; + sleep_queue_t* sq = nullptr; if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq) && mutex->attribute.ToBE() != se32(SYS_SYNC_RETRY)) { sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)", @@ -170,60 +172,89 @@ s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout) return CELL_ESRCH; } - auto old_owner = mutex->mutex.read_sync(); - if (old_owner != tid) + if (mutex->owner.read_sync() != 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; } - lw->m_queue.push(tid_le); + lw->queue.push(tid_le, mutex->attribute); auto old_recursive = mutex->recursive_count; mutex->recursive_count = 0; - be_t target = sq ? (be_t::make(mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) : be_t::make(0); - if (!mutex->mutex.compare_and_swap_test(tid, target)) + be_t target = be_t::make(sq->pop(mutex->attribute)); + if (!mutex->owner.compare_and_swap_test(tid, target)) { assert(!"sys_lwcond_wait(): mutex unlocking failed"); } - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : ~0; - + const u64 time_start = get_system_time(); while (true) { - if (lw->signal.unlock(tid, tid) == SMR_OK) + u32 signaled; + if (lw->signal.Peek(signaled, &sq_no_wait) && signaled == tid_le) // check signaled threads { - switch (mutex->lock(tid, 0)) + s32 res = mutex->lock(tid, timeout ? get_system_time() - time_start : 0); // this is bad + if (res == CELL_OK) { - case CELL_OK: break; - case static_cast(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked", - (u32)lwcond->lwcond_queue); return CELL_OK; - case static_cast(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(CELL_EINVAL): goto abort; + break; } - mutex->recursive_count = old_recursive; - lw->signal.unlock(tid); - return CELL_OK; + switch (res) + { + case static_cast(CELL_EDEADLK): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue); + lw->queue.invalidate(tid_le); + lw->signal.Pop(tid_le /* unused result */, nullptr); + return CELL_OK; // mutex not locked (but already locked in the incorrect way) + } + case static_cast(CELL_ESRCH): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); + lw->queue.invalidate(tid_le); + lw->signal.Pop(tid_le /* unused result */, nullptr); + return CELL_ESRCH; // mutex not locked + } + case static_cast(CELL_ETIMEDOUT): + { + lw->queue.invalidate(tid_le); + lw->signal.Pop(tid_le /* unused result */, nullptr); + return CELL_ETIMEDOUT; // mutex not locked + } + case static_cast(CELL_EINVAL): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); + lw->queue.invalidate(tid_le); + lw->signal.Pop(tid_le /* unused result */, nullptr); + return CELL_EINVAL; // mutex not locked + } + default: + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res); + lw->queue.invalidate(tid_le); + lw->signal.Pop(tid_le /* unused result */, nullptr); + return CELL_EINVAL; // mutex not locked + } + } } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (counter++ > max_counter) + if (timeout && get_system_time() - time_start > timeout) { - lw->m_queue.invalidate(tid_le); - return CELL_ETIMEDOUT; + lw->queue.invalidate(tid_le); + return CELL_ETIMEDOUT; // mutex not locked } + if (Emu.IsStopped()) { - goto abort; + sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); + return CELL_OK; } } -abort: - sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); + mutex->recursive_count = old_recursive; + lw->signal.Pop(tid_le /* unused result */, nullptr); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 5c34190776..4d5a37dd4d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -19,23 +19,24 @@ struct sys_lwcond_t struct Lwcond { - SMutex signal; - SleepQueue m_queue; + SQueue signal; + sleep_queue_t queue; Lwcond(u64 name) - : m_queue(name) + : queue(name) { - signal.initialize(); } }; // Aux s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64); +class PPUThread; + // SysCalls s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); s32 sys_lwcond_destroy(vm::ptr lwcond); s32 sys_lwcond_signal(vm::ptr lwcond); s32 sys_lwcond_signal_all(vm::ptr lwcond); s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id); -s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout); +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index dd78b03030..b27b3927c5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -6,33 +6,32 @@ #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" #include "sys_time.h" #include "sys_lwmutex.h" SysCallBase sys_lwmutex("sys_lwmutex"); -// TODO: move SleepQueue somewhere - s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) { LV2_LOCK(0); - lwmutex.mutex.write_relaxed(be_t::make(0)); + lwmutex.owner.write_relaxed(be_t::make(0)); lwmutex.waiter.write_relaxed(be_t::make(~0)); lwmutex.attribute = protocol | recursive; lwmutex.recursive_count = 0; - u32 sq_id = sys_lwmutex.GetNewId(new SleepQueue(name_u64), TYPE_LWMUTEX); + u32 sq_id = sys_lwmutex.GetNewId(new sleep_queue_t(name_u64), TYPE_LWMUTEX); lwmutex.sleep_queue = sq_id; std::string name((const char*)&name_u64, 8); sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", name.c_str(), protocol | recursive, sq_id); - Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, GetCurrentPPUThread().GetId()); + Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, 0); return CELL_OK; } -s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) +s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr) { sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); @@ -55,7 +54,7 @@ s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptrprotocol, attr->recursive, attr->name_u64); } -s32 sys_lwmutex_destroy(vm::ptr lwmutex) +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); @@ -77,156 +76,42 @@ s32 sys_lwmutex_destroy(vm::ptr lwmutex) } } -s32 sys_lwmutex_lock(vm::ptr lwmutex, u64 timeout) +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) { sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout); - return lwmutex->lock(be_t::make(GetCurrentPPUThread().GetId()), timeout); + return lwmutex->lock(be_t::make(CPU.GetId()), timeout); } -s32 sys_lwmutex_trylock(vm::ptr lwmutex) +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr()); - return lwmutex->trylock(be_t::make(GetCurrentPPUThread().GetId())); + return lwmutex->trylock(be_t::make(CPU.GetId())); } -s32 sys_lwmutex_unlock(vm::ptr lwmutex) +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr()); - return lwmutex->unlock(be_t::make(GetCurrentPPUThread().GetId())); -} - -void SleepQueue::push(u32 tid) -{ - std::lock_guard lock(m_mutex); - list.push_back(tid); -} - -u32 SleepQueue::pop() // SYS_SYNC_FIFO -{ - std::lock_guard lock(m_mutex); - - while (true) - { - if (list.size()) - { - u32 res = list[0]; - list.erase(list.begin()); - if (res && Emu.GetIdManager().CheckID(res)) - // check thread - { - return res; - } - } - return 0; - }; -} - -u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY -{ - std::lock_guard lock(m_mutex); - - while (true) - { - if (list.size()) - { - u64 highest_prio = ~0ull; - u32 sel = 0; - for (u32 i = 0; i < list.size(); i++) - { - CPUThread* t = Emu.GetCPU().GetThread(list[i]); - if (!t) - { - list[i] = 0; - sel = i; - break; - } - u64 prio = t->GetPrio(); - if (prio < highest_prio) - { - highest_prio = prio; - sel = i; - } - } - u32 res = list[sel]; - list.erase(list.begin() + sel); - /* if (Emu.GetIdManager().CheckID(res)) */ - if (res) - // check thread - { - return res; - } - } - return 0; - } -} - -u32 SleepQueue::pop_prio_inherit() // (TODO) -{ - sys_lwmutex.Error("TODO: SleepQueue::pop_prio_inherit()"); - Emu.Pause(); - return 0; -} - -bool SleepQueue::invalidate(u32 tid) -{ - std::lock_guard lock(m_mutex); - - if (tid) for (u32 i = 0; i < list.size(); i++) - { - if (list[i] == tid) - { - list.erase(list.begin() + i); - return true; - } - } - - return false; -} - -u32 SleepQueue::count() -{ - std::lock_guard lock(m_mutex); - - u32 result = 0; - for (u32 i = 0; i < list.size(); i++) - { - if (list[i]) result++; - } - return result; -} - -bool SleepQueue::finalize() -{ - if (!m_mutex.try_lock()) return false; - - for (u32 i = 0; i < list.size(); i++) - { - if (list[i]) - { - m_mutex.unlock(); - return false; - } - } - - m_mutex.unlock(); - return true; + return lwmutex->unlock(be_t::make(CPU.GetId())); } s32 sys_lwmutex_t::trylock(be_t tid) { if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; - be_t owner_tid = mutex.read_sync(); + const be_t old_owner = owner.read_sync(); - if (tid == owner_tid) + if (old_owner == tid) { if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) { recursive_count += 1; - if (!recursive_count.ToBE()) return CELL_EKRESOURCE; + if (!recursive_count.ToBE()) + { + return CELL_EKRESOURCE; + } return CELL_OK; } else @@ -235,7 +120,7 @@ s32 sys_lwmutex_t::trylock(be_t tid) } } - if (!mutex.compare_and_swap_test(be_t::make(0), tid)) + if (!owner.compare_and_swap_test(be_t::make(0), tid)) { return CELL_EBUSY; } @@ -246,45 +131,33 @@ s32 sys_lwmutex_t::trylock(be_t tid) s32 sys_lwmutex_t::unlock(be_t tid) { - if (mutex.read_sync() != tid) + if (owner.read_sync() != tid) { return CELL_EPERM; } - else + + if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) { - if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) - { - sys_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 target = be_t::make(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(); - } - } - - if (!mutex.compare_and_swap_test(tid, target)) - { - assert(!"sys_lwmutex_t::unlock() failed"); - } - } - - return CELL_OK; + sys_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()) + { + sleep_queue_t* sq; + if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) + { + return CELL_ESRCH; + } + + if (!owner.compare_and_swap_test(tid, be_t::make(sq->pop(attribute)))) + { + assert(!"sys_lwmutex_t::unlock() failed"); + } + } + + return CELL_OK; } s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) @@ -295,25 +168,18 @@ s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) default: return res; } - SleepQueue* sq; + sleep_queue_t* 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); - } - } + sq->push(tid, attribute); const u64 time_start = get_system_time(); while (true) { - auto old_owner = mutex.compare_and_swap(be_t::make(0), tid); + auto old_owner = owner.compare_and_swap(be_t::make(0), tid); if (!old_owner.ToBE()) { sq->invalidate(tid); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 354b9082bd..8a9e1b3212 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -1,31 +1,5 @@ #pragma once -// attr_protocol (waiting scheduling policy) -enum -{ - // First In, First Out - SYS_SYNC_FIFO = 1, - // Priority Order - SYS_SYNC_PRIORITY = 2, - // Basic Priority Inheritance Protocol (probably not implemented) - SYS_SYNC_PRIORITY_INHERIT = 3, - // Not selected while unlocking - SYS_SYNC_RETRY = 4, - // - SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, -}; - -// attr_recursive (recursive locks policy) -enum -{ - // Recursive locks are allowed - SYS_SYNC_RECURSIVE = 0x10, - // Recursive locks are NOT allowed - SYS_SYNC_NOT_RECURSIVE = 0x20, - // - SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? -}; - struct sys_lwmutex_attribute_t { be_t protocol; @@ -37,35 +11,9 @@ struct sys_lwmutex_attribute_t }; }; -struct SleepQueue -{ - /* struct q_rec - { - u32 tid; - u64 prio; - q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {} - }; */ - std::vector list; - std::mutex m_mutex; - u64 m_name; - - SleepQueue(u64 name = 0) - : m_name(name) - { - } - - void push(u32 tid); - u32 pop(); // SYS_SYNC_FIFO - u32 pop_prio(); // SYS_SYNC_PRIORITY - u32 pop_prio_inherit(); // (TODO) - bool invalidate(u32 tid); - u32 count(); - bool finalize(); -}; - struct sys_lwmutex_t { - atomic_t mutex; + atomic_t owner; atomic_t waiter; // currently not used be_t attribute; be_t recursive_count; @@ -85,9 +33,11 @@ struct sys_lwmutex_t // Aux s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); +class PPUThread; + // SysCalls -s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwmutex_destroy(vm::ptr lwmutex); -s32 sys_lwmutex_lock(vm::ptr lwmutex, u64 timeout); -s32 sys_lwmutex_trylock(vm::ptr lwmutex); -s32 sys_lwmutex_unlock(vm::ptr lwmutex); +s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr); +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index 6bf9439f02..8ba4f2777f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -3,33 +3,36 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/Memory/atomic_type.h" -#include "Utilities/SMutex.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_mutex.h" SysCallBase sys_mutex("sys_mutex"); Mutex::~Mutex() { - if (u32 owner = m_mutex.GetOwner()) + if (u32 tid = owner.read_sync()) { - sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, owner, recursive); + sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, tid, recursive); } - if (!m_queue.m_mutex.try_lock()) return; + if (!queue.m_mutex.try_lock()) return; - for (u32 i = 0; i < m_queue.list.size(); i++) + for (u32 i = 0; i < queue.list.size(); i++) { - if (u32 owner = m_queue.list[i]) sys_mutex.Notice("Mutex(%d) was waited by thread %d", id, owner); + if (u32 owner = queue.list[i]) + { + sys_mutex.Notice("Mutex(%d) was waited by thread %d", id, owner); + } } - m_queue.m_mutex.unlock(); + queue.m_mutex.unlock(); } -s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) +s32 sys_mutex_create(PPUThread& CPU, vm::ptr mutex_id, vm::ptr attr) { sys_mutex.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.addr(), attr.addr()); @@ -58,13 +61,10 @@ s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) return CELL_EINVAL; } - u32 tid = GetCurrentPPUThread().GetId(); Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64); - u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); - mutex->m_mutex.lock(tid); - mutex->id = id; + const u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); + mutex->id.exchange(id); *mutex_id = id; - mutex->m_mutex.unlock(tid); sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), id); @@ -74,7 +74,7 @@ s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) return CELL_OK; } -s32 sys_mutex_destroy(u32 mutex_id) +s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id) { sys_mutex.Warning("sys_mutex_destroy(mutex_id=%d)", mutex_id); @@ -91,26 +91,32 @@ s32 sys_mutex_destroy(u32 mutex_id) return CELL_EPERM; } - u32 tid = GetCurrentPPUThread().GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.trylock(tid)) // check if locked + if (mutex->owner.compare_and_swap_test(0, tid)) // check if locked { return CELL_EBUSY; } - if (!mutex->m_queue.finalize()) + if (!mutex->queue.finalize()) { - mutex->m_mutex.unlock(tid); + if (!mutex->owner.compare_and_swap_test(tid, 0)) + { + assert(!"sys_mutex_destroy() failed (busy)"); + } return CELL_EBUSY; } - mutex->m_mutex.unlock(tid, ~0); + if (!mutex->owner.compare_and_swap_test(tid, ~0)) + { + assert(!"sys_mutex_destroy() failed"); + } Emu.GetIdManager().RemoveID(mutex_id); Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_MUTEX, mutex_id); return CELL_OK; } -s32 sys_mutex_lock(u32 mutex_id, u64 timeout) +s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout) { sys_mutex.Log("sys_mutex_lock(mutex_id=%d, timeout=%lld)", mutex_id, timeout); @@ -120,14 +126,13 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout) return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + if (mutex->owner.read_sync() == tid) { if (mutex->is_recursive) { - if (++mutex->recursive == 0) + if (!++mutex->recursive) { return CELL_EKRESOURCE; } @@ -138,48 +143,51 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout) return CELL_EDEADLK; } } - else if (u32 owner = mutex->m_mutex.GetOwner()) - { - if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) - { - } - else - { - sys_mutex.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner); - } - } - switch (mutex->m_mutex.trylock(tid)) + if (mutex->owner.compare_and_swap_test(0, tid)) { - case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - case SMR_FAILED: break; - default: goto abort; - } - - mutex->m_queue.push(tid); - - switch (mutex->m_mutex.lock(tid, timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0)) - { - case SMR_OK: - mutex->m_queue.invalidate(tid); - case SMR_SIGNAL: - mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - case SMR_TIMEOUT: - mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT; - default: - mutex->m_queue.invalidate(tid); goto abort; - } - -abort: - if (Emu.IsStopped()) - { - sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id); + mutex->recursive = 1; + CPU.owned_mutexes++; return CELL_OK; } - return CELL_ESRCH; + + mutex->queue.push(tid, mutex->protocol); + + const u64 time_start = get_system_time(); + while (true) + { + auto old_owner = mutex->owner.compare_and_swap(0, tid); + if (!old_owner) + { + mutex->queue.invalidate(tid); + break; + } + if (old_owner == tid) + { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - time_start > timeout) + { + mutex->queue.invalidate(tid); + return CELL_ETIMEDOUT; + } + + if (Emu.IsStopped()) + { + sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id); + return CELL_OK; + } + } + + mutex->recursive = 1; + CPU.owned_mutexes++; + return CELL_OK; } -s32 sys_mutex_trylock(u32 mutex_id) +s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id) { sys_mutex.Log("sys_mutex_trylock(mutex_id=%d)", mutex_id); @@ -189,14 +197,13 @@ s32 sys_mutex_trylock(u32 mutex_id) return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + if (mutex->owner.read_sync() == tid) { if (mutex->is_recursive) { - if (++mutex->recursive == 0) + if (!++mutex->recursive) { return CELL_EKRESOURCE; } @@ -207,25 +214,18 @@ s32 sys_mutex_trylock(u32 mutex_id) return CELL_EDEADLK; } } - else if (u32 owner = mutex->m_mutex.GetOwner()) + + if (!mutex->owner.compare_and_swap_test(0, tid)) { - if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) - { - } - else - { - sys_mutex.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner); - } + return CELL_EBUSY; } - switch (mutex->m_mutex.trylock(tid)) - { - case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - default: return CELL_EBUSY; - } + mutex->recursive = 1; + CPU.owned_mutexes++; + return CELL_OK; } -s32 sys_mutex_unlock(u32 mutex_id) +s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id) { sys_mutex.Log("sys_mutex_unlock(mutex_id=%d)", mutex_id); @@ -235,24 +235,26 @@ s32 sys_mutex_unlock(u32 mutex_id) return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + if (mutex->owner.read_sync() != tid) { - if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive)) - { - sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive); - mutex->recursive = 1; - } - mutex->recursive--; - if (!mutex->recursive) - { - mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); - t.owned_mutexes--; - } - return CELL_OK; + return CELL_EPERM; } - return CELL_EPERM; + if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive)) + { + sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive); + mutex->recursive = 1; + } + + if (!--mutex->recursive) + { + if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol))) + { + assert(!"sys_mutex_unlock() failed"); + } + CPU.owned_mutexes--; + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h index 6a8843fb68..14b4548ab7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h @@ -18,9 +18,9 @@ struct sys_mutex_attribute struct Mutex { - u32 id; - SMutex m_mutex; - SleepQueue m_queue; + atomic_le_t id; + atomic_le_t owner; + sleep_queue_t queue; u32 recursive; // recursive locks count std::atomic cond_count; // count of condition variables associated @@ -30,18 +30,20 @@ struct Mutex Mutex(u32 protocol, bool is_recursive, u64 name) : protocol(protocol) , is_recursive(is_recursive) - , m_queue(name) + , queue(name) , cond_count(0) { - m_mutex.initialize(); + owner.write_relaxed(0); } ~Mutex(); }; +class PPUThread; + // SysCalls -s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr); -s32 sys_mutex_destroy(u32 mutex_id); -s32 sys_mutex_lock(u32 mutex_id, u64 timeout); -s32 sys_mutex_trylock(u32 mutex_id); -s32 sys_mutex_unlock(u32 mutex_id); +s32 sys_mutex_create(PPUThread& CPU, vm::ptr mutex_id, vm::ptr attr); +s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id); +s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout); +s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id); +s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index e60882bc21..0a759cdc2f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -43,7 +43,7 @@ s32 sys_ppu_thread_yield() { sys_ppu_thread.Log("sys_ppu_thread_yield()"); // Note: Or do we actually want to yield? - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_OK; } @@ -61,7 +61,7 @@ s32 sys_ppu_thread_join(u64 thread_id, vm::ptr vptr) sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } *vptr = thr->GetExitStatus(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp index b4c9f8e77b..678f46bfe7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp @@ -5,7 +5,7 @@ #include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" #include "sys_rwlock.h" SysCallBase sys_rwlock("sys_rwlock"); @@ -76,7 +76,7 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout) sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, ...) aborted", rw_lock_id); return CELL_ETIMEDOUT; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (rw->rlock_trylock(tid)) return CELL_OK; @@ -139,7 +139,7 @@ s32 sys_rwlock_wlock(u32 rw_lock_id, u64 timeout) sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, ...) aborted", rw_lock_id); return CELL_ETIMEDOUT; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (rw->wlock_trylock(tid, true)) return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index ab1de1d1b6..e68bf58c6c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -6,7 +6,7 @@ #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" #include "sys_time.h" #include "sys_semaphore.h" @@ -75,7 +75,7 @@ s32 sys_semaphore_destroy(u32 sem_id) return CELL_ESRCH; } - if (!sem->m_queue.finalize()) + if (!sem->queue.finalize()) { return CELL_EBUSY; } @@ -99,13 +99,13 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout) const u64 start_time = get_system_time(); { - std::lock_guard lock(sem->m_mutex); - if (sem->m_value > 0) + std::lock_guard lock(sem->mutex); + if (sem->value > 0) { - sem->m_value--; + sem->value--; return CELL_OK; } - sem->m_queue.push(tid); + sem->queue.push(tid, sem->protocol); } while (true) @@ -118,13 +118,13 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout) if (timeout && get_system_time() - start_time > timeout) { - sem->m_queue.invalidate(tid); + sem->queue.invalidate(tid); return CELL_ETIMEDOUT; } if (tid == sem->signal) { - std::lock_guard lock(sem->m_mutex); + std::lock_guard lock(sem->mutex); if (tid != sem->signal) { @@ -134,7 +134,7 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout) return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } } @@ -148,11 +148,11 @@ s32 sys_semaphore_trywait(u32 sem_id) return CELL_ESRCH; } - std::lock_guard lock(sem->m_mutex); + std::lock_guard lock(sem->mutex); - if (sem->m_value > 0) + if (sem->value > 0) { - sem->m_value--; + sem->value--; return CELL_OK; } else @@ -176,7 +176,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) return CELL_EINVAL; } - if (count + sem->m_value - (s32)sem->m_queue.count() > sem->max) + if (count + sem->value - (s32)sem->queue.count() > sem->max) { return CELL_EBUSY; } @@ -189,22 +189,22 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) return CELL_OK; } - std::lock_guard lock(sem->m_mutex); + std::lock_guard lock(sem->mutex); - if (sem->signal && sem->m_queue.count()) + if (sem->signal && sem->queue.count()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } - if (u32 target = (sem->protocol == SYS_SYNC_FIFO) ? sem->m_queue.pop() : sem->m_queue.pop_prio()) + if (u32 target = sem->queue.pop(sem->protocol)) { count--; sem->signal = target; } else { - sem->m_value += count; + sem->value += count; count = 0; } } @@ -227,9 +227,9 @@ s32 sys_semaphore_get_value(u32 sem_id, vm::ptr count) return CELL_ESRCH; } - std::lock_guard lock(sem->m_mutex); + std::lock_guard lock(sem->mutex); - *count = sem->m_value; + *count = sem->value; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h index 30d034cea2..22e8725ee1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h @@ -16,9 +16,9 @@ struct sys_semaphore_attribute struct Semaphore { - std::mutex m_mutex; - SleepQueue m_queue; - s32 m_value; + std::mutex mutex; + sleep_queue_t queue; + s32 value; u32 signal; const s32 max; @@ -26,7 +26,7 @@ struct Semaphore const u64 name; Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name) - : m_value(initial_count) + : value(initial_count) , signal(0) , max(max_count) , protocol(protocol) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp index 4a24c2b520..519cf44069 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp @@ -59,4 +59,4 @@ void sys_spinlock_unlock(vm::ptr> lock) // prx: sync and set 0 lock->exchange(be_t::make(0)); -} \ No newline at end of file +} diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 4a4a1a5523..b033473a7c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -504,7 +504,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status) sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 4c271aaac9..dc661ddf68 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -362,7 +362,6 @@ void Emulator::Stop() m_status = Stopped; u32 uncounted = 0; - u32 counter = 0; while (true) { if (g_thread_count <= uncounted) diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index b0990ba2f6..b465f70e76 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -50,7 +50,6 @@ - @@ -134,6 +133,7 @@ + @@ -277,7 +277,6 @@ - @@ -383,6 +382,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 9335c19690..92eaaf8acc 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -383,9 +383,6 @@ Source Files - - Utilities - Utilities @@ -653,6 +650,9 @@ Emu\CPU\ARMv7\Modules + + Emu\SysCalls\lv2 + @@ -1009,9 +1009,6 @@ Utilities - - Utilities - Utilities @@ -1261,5 +1258,8 @@ Emu\CPU\ARMv7 + + Emu\SysCalls\lv2 + \ No newline at end of file