diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index c6e4f7c01a..4e3b317a9d 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -4,6 +4,8 @@ template class SQueue { std::mutex m_mutex; + NamedThreadBase* push_waiter; + NamedThreadBase* pop_waiter; u32 m_pos; u32 m_count; T m_data[SQSize]; @@ -12,6 +14,8 @@ public: SQueue() : m_pos(0) , m_count(0) + , push_waiter(nullptr) + , pop_waiter(nullptr) { } @@ -22,6 +26,9 @@ public: bool Push(const T& data) { + NamedThreadBase* t = GetCurrentNamedThread(); + push_waiter = t; + while (true) { if (m_count >= SQSize) @@ -30,7 +37,8 @@ public: { return false; } - Sleep(1); + + SM_Sleep(); continue; } @@ -38,9 +46,11 @@ public: std::lock_guard lock(m_mutex); if (m_count >= SQSize) continue; + if (pop_waiter && !m_count) pop_waiter->Notify(); m_data[(m_pos + m_count++) % SQSize] = data; + push_waiter = nullptr; return true; } } @@ -48,6 +58,9 @@ public: bool Pop(T& data) { + NamedThreadBase* t = GetCurrentNamedThread(); + pop_waiter = t; + while (true) { if (!m_count) @@ -56,7 +69,8 @@ public: { return false; } - Sleep(1); + + SM_Sleep(); continue; } @@ -64,22 +78,24 @@ public: std::lock_guard lock(m_mutex); if (!m_count) continue; + if (push_waiter && m_count >= SQSize) push_waiter->Notify(); data = m_data[m_pos]; m_pos = (m_pos + 1) % SQSize; m_count--; + pop_waiter = nullptr; return true; } } } - volatile u32 GetCount() // may be not safe + volatile u32 GetCount() // may be thread unsafe { return m_count; } - volatile bool IsEmpty() // may be not safe + volatile bool IsEmpty() // may be thread unsafe { return !m_count; } @@ -87,11 +103,15 @@ public: void Clear() { std::lock_guard lock(m_mutex); + if (push_waiter && m_count >= SQSize) push_waiter->Notify(); m_count = 0; } T& Peek(u32 pos = 0) { + NamedThreadBase* t = GetCurrentNamedThread(); + pop_waiter = t; + while (true) { if (!m_count) @@ -100,13 +120,18 @@ public: { break; } - Sleep(1); + + SM_Sleep(); continue; } { std::lock_guard lock(m_mutex); - if (m_count) break; + if (m_count) + { + pop_waiter = nullptr; + break; + } } } return m_data[(m_pos + pos) % SQSize]; diff --git a/Utilities/SSemaphore.cpp b/Utilities/SSemaphore.cpp new file mode 100644 index 0000000000..91754b764f --- /dev/null +++ b/Utilities/SSemaphore.cpp @@ -0,0 +1,75 @@ +#include "stdafx.h" +#include "Utilities/SSemaphore.h" + +bool SSemaphore::wait(u64 timeout) +{ + std::unique_lock lock(m_cv_mutex); + + u64 counter = 0; + while (true) + { + if (Emu.IsStopped()) + { + return false; + } + if (timeout && counter >= timeout) + { + return false; + } + m_cond.wait_for(lock, std::chrono::milliseconds(1)); + counter++; + + std::lock_guard lock(m_mutex); + if (m_count) + { + m_count--; + return true; + } + } +} + +bool SSemaphore::try_wait() +{ + std::lock_guard lock(m_mutex); + + if (m_count) + { + m_count--; + return true; + } + else + { + return false; + } +} + +void SSemaphore::post(u32 value) +{ + std::lock_guard lock(m_mutex); + + if (m_count >= m_max) + { + value = 0; + } + else if (value > (m_max - m_count)) + { + value = m_max - m_count; + } + + while (value) + { + m_count++; + value--; + m_cond.notify_one(); + } +} + +bool SSemaphore::post_and_wait() +{ + if (try_wait()) return false; + + post(); + wait(); + + return true; +} \ No newline at end of file diff --git a/Utilities/SSemaphore.h b/Utilities/SSemaphore.h new file mode 100644 index 0000000000..af46997bbf --- /dev/null +++ b/Utilities/SSemaphore.h @@ -0,0 +1,34 @@ +#pragma once + +class SSemaphore +{ + const u32 m_max; + u32 m_count; + std::mutex m_mutex, m_cv_mutex; + std::condition_variable m_cond; + +public: + SSemaphore(u32 value, u32 max = 1) + : m_max(max > 0 ? max : 0xffffffff) + , m_count(value > m_max ? m_max : value) + { + } + + SSemaphore() + : m_max(0xffffffff) + , m_count(0) + { + } + + ~SSemaphore() + { + } + + bool wait(u64 timeout = 0); + + bool try_wait(); + + void post(u32 value = 1); + + bool post_and_wait(); +}; \ No newline at end of file diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 7a4065015b..4485227e2d 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -6,6 +6,7 @@ #include #include #include +#include class ThreadExec; @@ -138,16 +139,6 @@ public: bool IsBusy() const { return m_busy; } }; -static __forceinline bool SemaphorePostAndWait(rSemaphore& sem) -{ - if(sem.TryWait() != rSEMA_BUSY) return false; - - sem.Post(); - sem.Wait(); - - return true; -} - /* class StepThread : public ThreadBase { diff --git a/rpcs3/Emu/GS/GSRender.h b/rpcs3/Emu/GS/GSRender.h index 5f55543327..556c889606 100644 --- a/rpcs3/Emu/GS/GSRender.h +++ b/rpcs3/Emu/GS/GSRender.h @@ -32,8 +32,8 @@ public: switch(m_type) { case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.Enter(); break; - case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.Wait(); break; - case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.Wait(); break; + case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.wait(); break; + case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.wait(); break; } } @@ -42,8 +42,8 @@ public: switch(m_type) { case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.Leave(); break; - case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.Post(); break; - case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.Post(); break; + case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.post(); break; + case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.post(); break; } } }; diff --git a/rpcs3/Emu/GS/RSXThread.cpp b/rpcs3/Emu/GS/RSXThread.cpp index 5c76ab3792..8f5b9f2d1a 100644 --- a/rpcs3/Emu/GS/RSXThread.cpp +++ b/rpcs3/Emu/GS/RSXThread.cpp @@ -1891,9 +1891,9 @@ void RSXThread::Task() if(put == get) { if(m_flip_status == 0) - SemaphorePostAndWait(m_sem_flip); + m_sem_flip.post_and_wait(); - SemaphorePostAndWait(m_sem_flush); + m_sem_flush.post_and_wait(); } Sleep(1); diff --git a/rpcs3/Emu/GS/RSXThread.h b/rpcs3/Emu/GS/RSXThread.h index 2a5020c12e..96166d4c0f 100644 --- a/rpcs3/Emu/GS/RSXThread.h +++ b/rpcs3/Emu/GS/RSXThread.h @@ -7,6 +7,7 @@ #include #include // For tracking a list of used gcm commands +#include "Utilities/SSemaphore.h" enum Method { @@ -146,8 +147,8 @@ public: public: rCriticalSection m_cs_main; - rSemaphore m_sem_flush; - rSemaphore m_sem_flip; + SSemaphore m_sem_flush; + SSemaphore m_sem_flip; Callback m_flip_handler; public: diff --git a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp index 9e31b63c62..94b9f9f969 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp @@ -147,10 +147,21 @@ int sys_ppu_thread_restart(u32 thread_id) int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr) { - sysPrxForUser->Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%x, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x('%s'))", - thread_id_addr, entry, arg, prio, stacksize, flags, threadname_addr, Memory.ReadString(threadname_addr).c_str()); + std::string threadname = ""; + if (Memory.IsGoodAddr(threadname_addr)) + { + threadname = Memory.ReadString(threadname_addr); + sysPrxForUser->Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%x, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x('%s'))", + thread_id_addr, entry, arg, prio, stacksize, flags, threadname_addr, threadname.c_str()); + } + else + { + sysPrxForUser->Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%x, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x)", + thread_id_addr, entry, arg, prio, stacksize, flags, threadname_addr); + if (threadname_addr != 0) return CELL_EFAULT; + } - if(!Memory.IsGoodAddr(entry) || !Memory.IsGoodAddr(thread_id_addr) || !Memory.IsGoodAddr(threadname_addr)) + if(!Memory.IsGoodAddr(entry) || !Memory.IsGoodAddr(thread_id_addr)) { return CELL_EFAULT; } @@ -163,7 +174,7 @@ int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u64 arg, int prio, u32 new_thread.SetPrio(prio); new_thread.SetStackSize(stacksize); //new_thread.flags = flags; - new_thread.SetName(Memory.ReadString(threadname_addr)); + new_thread.SetName(threadname); ConLog.Write("*** New PPU Thread [%s] (): id = %d", new_thread.GetName().c_str(), new_thread.GetId()); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 4e8b8bd3ab..25be8d5571 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -28,6 +28,7 @@ + @@ -220,6 +221,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index a5db320871..4f530fafa5 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -575,6 +575,9 @@ Emu\Io\XInput + + Utilities + @@ -1042,5 +1045,8 @@ Emu\SysCalls + + Utilities + \ No newline at end of file