From 89fad4d3ad80b6fbc68f173372db1fea52e79351 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 19:36:45 +0100 Subject: [PATCH 01/15] common: port ScopedPtrMT to std::atomic v2: s/NULL/nullptr/ v3: tentative fix for MSVC // ScopedPtrMT.h(91, 0): error C2593: 'operator ==' is ambiguous --- common/include/Utilities/Dependencies.h | 3 ++- common/include/Utilities/ScopedPtrMT.h | 34 +++++++++++-------------- common/include/Utilities/Threading.h | 6 ----- common/src/Utilities/ThreadTools.cpp | 18 ------------- 4 files changed, 17 insertions(+), 44 deletions(-) diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 31bc649149..80733a2676 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -190,7 +190,7 @@ public: // (I think it's unsigned int vs signed int) #include #define HAVE_MODE_T -#endif +#endif #include #include // string.h under c++ @@ -200,6 +200,7 @@ public: #include #include #include +#include #include "Pcsx2Defs.h" diff --git a/common/include/Utilities/ScopedPtrMT.h b/common/include/Utilities/ScopedPtrMT.h index d8dab7edbc..9c5c0dc1db 100644 --- a/common/include/Utilities/ScopedPtrMT.h +++ b/common/include/Utilities/ScopedPtrMT.h @@ -27,25 +27,23 @@ class ScopedPtrMT { DeclareNoncopyableObject(ScopedPtrMT); - typedef T* TPtr; - protected: - volatile TPtr m_ptr; + std::atomic m_ptr; Threading::Mutex m_mtx; public: typedef T element_type; - wxEXPLICIT ScopedPtrMT(T * ptr = NULL) + wxEXPLICIT ScopedPtrMT(T * ptr = nullptr) { m_ptr = ptr; } ~ScopedPtrMT() throw() { _Delete_unlocked(); } - ScopedPtrMT& Reassign(T * ptr = NULL) + ScopedPtrMT& Reassign(T * ptr = nullptr) { - TPtr doh = (TPtr)Threading::AtomicExchangePointer( m_ptr, ptr ); + T* doh = m_ptr.exchange(ptr); if ( ptr != doh ) delete doh; return *this; } @@ -55,19 +53,17 @@ public: ScopedLock lock( m_mtx ); _Delete_unlocked(); } - + // Removes the pointer from scoped management, but does not delete! - // (ScopedPtr will be NULL after this method) + // (ScopedPtr will be nullptr after this method) T *DetachPtr() { ScopedLock lock( m_mtx ); - T *ptr = m_ptr; - m_ptr = NULL; - return ptr; + return m_ptr.exchange(nullptr); } - // Returns the managed pointer. Can return NULL as a valid result if the ScopedPtrMT + // Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT // has no object in management. T* GetPtr() const { @@ -77,6 +73,7 @@ public: void SwapPtr(ScopedPtrMT& other) { ScopedLock lock( m_mtx ); + m_ptr.exchange(other.m_ptr.exchange(m_ptr.load())); T * const tmp = other.m_ptr; other.m_ptr = m_ptr; m_ptr = tmp; @@ -91,7 +88,7 @@ public: bool operator!() const throw() { - return m_ptr == NULL; + return m_ptr.load() == nullptr; } // Equality @@ -106,7 +103,7 @@ public: return !operator==(pT); } - // Convenient assignment operator. ScopedPtrMT = NULL will issue an automatic deletion + // Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion // of the managed pointer. ScopedPtrMT& operator=( T* src ) { @@ -120,16 +117,16 @@ public: } // Dereference operator, returns a handle to the managed pointer. - // Generates a debug assertion if the object is NULL! + // Generates a debug assertion if the object is nullptr! T& operator*() const { - pxAssert(m_ptr != NULL); + pxAssert(m_ptr != nullptr); return *m_ptr; } T* operator->() const { - pxAssert(m_ptr != NULL); + pxAssert(m_ptr != nullptr); return m_ptr; } #endif @@ -137,7 +134,6 @@ public: protected: void _Delete_unlocked() throw() { - delete m_ptr; - m_ptr = NULL; + delete m_ptr.exchange(nullptr); } }; diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 6f2cfcb71f..be0244db50 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -192,12 +192,6 @@ namespace Threading extern bool AtomicBitTestAndReset( volatile u32& bitset, u8 bit ); extern bool AtomicBitTestAndReset( volatile s32& bitset, u8 bit ); - extern void* _AtomicExchangePointer( volatile uptr& target, uptr value ); - extern void* _AtomicCompareExchangePointer( volatile uptr& target, uptr value, uptr comparand ); - -#define AtomicExchangePointer( dest, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)src ) -#define AtomicCompareExchangePointer( dest, comp, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)comp, (uptr)src ) - // pthread Cond is an evil api that is not suited for Pcsx2 needs. // Let's not use it. Use mutexes and semaphores instead to create waits. (Air) #if 0 diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 87f071cbdb..324abca580 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -828,24 +828,6 @@ __fi s32 Threading::AtomicDecrement(volatile s32& Target) { return _InterlockedExchangeAdd((volatile vol_t*)&Target, -1); } -__fi void* Threading::_AtomicExchangePointer(volatile uptr& target, uptr value) -{ -#ifdef _M_X86_64 // high-level atomic ops, please leave these 64 bit checks in place. - return (void*)_InterlockedExchange64((volatile s64*)&target, value); -#else - return (void*)_InterlockedExchange((volatile vol_t*)&target, value); -#endif -} - -__fi void* Threading::_AtomicCompareExchangePointer(volatile uptr& target, uptr value, uptr comparand) -{ -#ifdef _M_X86_64 // high-level atomic ops, please leave these 64 bit checks in place. - return (void*)_InterlockedCompareExchange64((volatile s64*)&target, value, comparand); -#else - return (void*)_InterlockedCompareExchange((volatile vol_t*)&target, value, comparand); -#endif -} - // -------------------------------------------------------------------------------------- // BaseThreadError // -------------------------------------------------------------------------------------- From 60fe26ff2f49c72dfee87d96fb35f68eaeb02a6f Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 19:55:39 +0100 Subject: [PATCH 02/15] common:threading: Port NonblockingMutex to std::atomic_flag --- common/include/Utilities/Threading.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index be0244db50..b50fa2e2d8 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -222,23 +222,24 @@ namespace Threading class NonblockingMutex { protected: - volatile int val; + std::atomic_flag val; public: - NonblockingMutex() : val( false ) {} + NonblockingMutex() { val.clear(); } virtual ~NonblockingMutex() throw() {} bool TryAcquire() throw() { - return !AtomicExchange( val, true ); + return !val.test_and_set(); } + // Can be done with a TryAcquire/Release but it is likely better to do it outside of the object bool IsLocked() - { return !!val; } + { pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex"); return false; } void Release() { - AtomicExchange( val, false ); + val.clear(); } }; From e5d4f2c24f9db1ecf53ad54ae9fb65343a2b4a24 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 20:09:53 +0100 Subject: [PATCH 03/15] EE: use std::atomic for reset variable --- pcsx2/x86/ix86-32/iR5900-32.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 6093792147..a40e9f6b74 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -566,8 +566,8 @@ static void recAlloc() static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12]; static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12]; -static u32 eeRecIsReset = false; -static u32 eeRecNeedsReset = false; +static std::atomic eeRecIsReset(false); +static std::atomic eeRecNeedsReset(false); static bool eeCpuExecuting = false; //////////////////////////////////////////////////// @@ -579,8 +579,8 @@ static void recResetRaw() recAlloc(); - if( AtomicExchange( eeRecIsReset, true ) ) return; - AtomicExchange( eeRecNeedsReset, false ); + if( eeRecIsReset.exchange(true) ) return; + eeRecNeedsReset = false; Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); @@ -628,7 +628,7 @@ static void recResetEE() { if (eeCpuExecuting) { - AtomicExchange( eeRecNeedsReset, true ); + eeRecNeedsReset = true; return; } @@ -1561,11 +1561,11 @@ static void __fastcall recRecompile( const u32 startpc ) // if recPtr reached the mem limit reset whole mem if (recPtr >= (recMem->GetPtrEnd() - _64kb)) { - AtomicExchange( eeRecNeedsReset, true ); + eeRecNeedsReset = true; } else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) { Console.WriteLn("EE recompiler stack reset"); - AtomicExchange( eeRecNeedsReset, true ); + eeRecNeedsReset = true; } if (eeRecNeedsReset) recResetRaw(); @@ -1633,7 +1633,7 @@ static void __fastcall recRecompile( const u32 startpc ) xFastCall(GoemonPreloadTlb); } else if (pc == 0x3563b8) { // Game will unmap some virtual addresses. If a constant address were hardcoded in the block, we would be in a bad situation. - AtomicExchange( eeRecNeedsReset, true ); + eeRecNeedsReset = true; // 0x3563b8 is the start address of the function that invalidate entry in TLB cache xFastCall(GoemonUnloadTlb, ptr[&cpuRegs.GPR.n.a0.UL[0]]); } From 97cc468509236224af2a616c0e7a38181b5bb979 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 20:15:15 +0100 Subject: [PATCH 04/15] gui: use std::atomic bool to manage the gui V2: Don't use 64 bits atomic (I'm not sure it is legal on 32 bits) Note: Clang-3.7 fails to link --- pcsx2/gui/AppConfig.cpp | 6 +++--- pcsx2/gui/AppCoreThread.cpp | 2 +- pcsx2/gui/AppCoreThread.h | 6 +++--- pcsx2/gui/ConsoleLogger.h | 12 ++++++------ pcsx2/gui/ExecutorThread.cpp | 4 ++-- pcsx2/gui/Saveslots.cpp | 8 ++++---- pcsx2/gui/pxEventThread.h | 6 ++++-- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 285dcee342..13007cd788 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -1319,11 +1319,11 @@ void AppSaveSettings() // If multiple SaveSettings messages are requested, we want to ignore most of them. // Saving settings once when the GUI is idle should be fine. :) - static u32 isPosted = false; + static std::atomic isPosted(false); if( !wxThread::IsMain() ) { - if( !AtomicExchange(isPosted, true) ) + if( !isPosted.exchange(true) ) wxGetApp().PostIdleMethod( AppSaveSettings ); return; @@ -1335,7 +1335,7 @@ void AppSaveSettings() SaveVmSettings(); SaveRegSettings(); // save register because of PluginsFolder change - AtomicExchange( isPosted, false ); + isPosted = false; } diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 20589b2d07..3b000ec026 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -483,7 +483,7 @@ void AppCoreThread::OnResumeInThread( bool isSuspended ) GetCorePlugins().Close( PluginId_CDVD ); CDVDsys_ChangeSource( g_Conf->CdvdSource ); cdvdCtrlTrayOpen(); - m_resetCdvd = false; + m_resetCdvd = false; } _parent::OnResumeInThread( isSuspended ); diff --git a/pcsx2/gui/AppCoreThread.h b/pcsx2/gui/AppCoreThread.h index 6e49661953..29aff5e4db 100644 --- a/pcsx2/gui/AppCoreThread.h +++ b/pcsx2/gui/AppCoreThread.h @@ -123,12 +123,12 @@ class AppCoreThread : public SysCoreThread typedef SysCoreThread _parent; protected: - volatile bool m_resetCdvd; - + std::atomic m_resetCdvd; + public: AppCoreThread(); virtual ~AppCoreThread() throw(); - + void ResetCdvd() { m_resetCdvd = true; } virtual void Suspend( bool isBlocking=false ); diff --git a/pcsx2/gui/ConsoleLogger.h b/pcsx2/gui/ConsoleLogger.h index 674e401723..d8e3b741fd 100644 --- a/pcsx2/gui/ConsoleLogger.h +++ b/pcsx2/gui/ConsoleLogger.h @@ -77,7 +77,7 @@ class ConsoleTestThread : public Threading::pxThread typedef pxThread _parent; protected: - volatile bool m_done; + std::atomic m_done; void ExecuteTaskInThread(); public: @@ -176,22 +176,22 @@ protected: int m_flushevent_counter; bool m_FlushRefreshLocked; - + // ---------------------------------------------------------------------------- // Queue State Management Vars // ---------------------------------------------------------------------------- // Boolean indicating if a flush message is already in the Main message queue. Used // to prevent spamming the main thread with redundant messages. - volatile bool m_pendingFlushMsg; + std::atomic m_pendingFlushMsg; // This is a counter of the number of threads waiting for the Queue to flush. - volatile int m_WaitingThreadsForFlush; + std::atomic m_WaitingThreadsForFlush; // Indicates to the main thread if a child thread is actively writing to the log. If // true the main thread will sleep briefly to allow the child a chance to accumulate // more messages (helps avoid rapid successive flushes on high volume logging). - volatile bool m_ThreadedLogInQueue; + std::atomic m_ThreadedLogInQueue; // Used by threads waiting on the queue to flush. Semaphore m_sem_QueueFlushed; @@ -258,6 +258,6 @@ protected: void OnMoveAround( wxMoveEvent& evt ); void OnResize( wxSizeEvent& evt ); void OnActivate( wxActivateEvent& evt ); - + void OnLoggingChanged(); }; diff --git a/pcsx2/gui/ExecutorThread.cpp b/pcsx2/gui/ExecutorThread.cpp index 30f326f2d4..2651be716b 100644 --- a/pcsx2/gui/ExecutorThread.cpp +++ b/pcsx2/gui/ExecutorThread.cpp @@ -158,7 +158,7 @@ void SysExecEvent::PostResult() const // -------------------------------------------------------------------------------------- pxEvtQueue::pxEvtQueue() { - AtomicExchange( m_Quitting, false ); + m_Quitting = false; m_qpc_Start = 0; } @@ -171,7 +171,7 @@ pxEvtQueue::pxEvtQueue() void pxEvtQueue::ShutdownQueue() { if( m_Quitting ) return; - AtomicExchange( m_Quitting, true ); + m_Quitting = true; m_wakeup.Post(); } diff --git a/pcsx2/gui/Saveslots.cpp b/pcsx2/gui/Saveslots.cpp index 9f0051b9eb..c742db2e5c 100644 --- a/pcsx2/gui/Saveslots.cpp +++ b/pcsx2/gui/Saveslots.cpp @@ -40,7 +40,7 @@ bool States_isSlotUsed(int num) // FIXME : Use of the IsSavingOrLoading flag is mostly a hack until we implement a // complete thread to manage queuing savestate tasks, and zipping states to disk. --air -static volatile u32 IsSavingOrLoading = false; +static std::atomic IsSavingOrLoading(false); class SysExecEvent_ClearSavingLoadingFlag : public SysExecEvent { @@ -57,7 +57,7 @@ public: protected: void InvokeEvent() { - AtomicExchange(IsSavingOrLoading, false); + IsSavingOrLoading = false; } }; @@ -73,7 +73,7 @@ void States_FreezeCurrentSlot() return; } - if( wxGetApp().HasPendingSaves() || AtomicExchange(IsSavingOrLoading, true) ) + if( wxGetApp().HasPendingSaves() || IsSavingOrLoading.exchange(true) ) { Console.WriteLn( "Load or save action is already pending." ); return; @@ -94,7 +94,7 @@ void _States_DefrostCurrentSlot( bool isFromBackup ) return; } - if( AtomicExchange(IsSavingOrLoading, true) ) + if( IsSavingOrLoading.exchange(true) ) { Console.WriteLn( "Load or save action is already pending." ); return; diff --git a/pcsx2/gui/pxEventThread.h b/pcsx2/gui/pxEventThread.h index 56f4ca973c..796cdcec84 100644 --- a/pcsx2/gui/pxEventThread.h +++ b/pcsx2/gui/pxEventThread.h @@ -204,11 +204,13 @@ protected: Threading::MutexRecursive m_mtx_pending; Threading::Semaphore m_wakeup; wxThreadIdType m_OwnerThreadId; - volatile u32 m_Quitting; + std::atomic m_Quitting; // Used for performance measuring the execution of individual events, // and also for detecting deadlocks during message processing. - volatile u64 m_qpc_Start; + // Clang-3.7 failed to link (maybe 64 bits atomic isn't supported on 32 bits) + // std::atomic m_qpc_Start; + u64 m_qpc_Start; public: pxEvtQueue(); From 34826c9506c1e7957bae39ebbef13ff567a9c07f Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 20:17:43 +0100 Subject: [PATCH 05/15] PluginManager: port to std::atomic --- pcsx2/PluginManager.cpp | 4 ++-- pcsx2/Plugins.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index 8e0f3d3229..1a29b8db19 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -1213,7 +1213,7 @@ void SysCorePlugins::Open() if (GSopen2) GetMTGS().WaitForOpen(); - if( !AtomicExchange( m_mcdOpen, true ) ) + if( !m_mcdOpen.exchange(true) ) { DbgCon.Indent().WriteLn( "Opening Memorycards"); OpenPlugin_Mcd(); @@ -1313,7 +1313,7 @@ void SysCorePlugins::Close() Console.WriteLn( Color_StrongBlue, "Closing plugins..." ); - if( AtomicExchange( m_mcdOpen, false ) ) + if( m_mcdOpen.exchange(false) ) { DbgCon.Indent().WriteLn( "Closing Memorycards"); ClosePlugin_Mcd(); diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 4e4a15e82c..1bfe4f6629 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -295,7 +295,7 @@ protected: Threading::MutexRecursive m_mtx_PluginStatus; // Lovely hack until the new PS2E API is completed. - volatile u32 m_mcdOpen; + std::atomic m_mcdOpen; public: // hack until we unsuck plugins... std::unique_ptr m_info[PluginId_AllocCount]; From 92078b1c5872764ea4e16613cebbff99deaf3f55 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 20:32:41 +0100 Subject: [PATCH 06/15] System: port to std::atomic v2: use an explicit int type for clang // multiple conversions from switch condition type // 'std::atomic' to an integral or enumeration type v3/v4: use .load to read variable (clang 3.7) v5: add back 'std::atomic' now that .load is used everywhere --- pcsx2/System/SysThreadBase.cpp | 6 +++--- pcsx2/System/SysThreads.h | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pcsx2/System/SysThreadBase.cpp b/pcsx2/System/SysThreadBase.cpp index a92f9836e4..3845b2c889 100644 --- a/pcsx2/System/SysThreadBase.cpp +++ b/pcsx2/System/SysThreadBase.cpp @@ -91,7 +91,7 @@ void SysThreadBase::Suspend( bool isBlocking ) { ScopedLock locker( m_ExecModeMutex ); - switch( m_ExecMode ) + switch( m_ExecMode.load() ) { // Invalid thread state, nothing to suspend case ExecMode_NoThreadYet: @@ -196,7 +196,7 @@ void SysThreadBase::Resume() // sanity checks against m_ExecMode/m_Running status, and if something doesn't feel // right, we should abort; the user may have canceled the action before it even finished. - switch( m_ExecMode ) + switch( m_ExecMode.load() ) { case ExecMode_Opened: return; @@ -267,7 +267,7 @@ void SysThreadBase::OnResumeInThread( bool isSuspended ) {} // continued execution unimpeded. bool SysThreadBase::StateCheckInThread() { - switch( m_ExecMode ) + switch( m_ExecMode.load() ) { #ifdef PCSX2_DEVBUILD // optimize out handlers for these cases in release builds. diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index 853ad4d735..caead7ba25 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -63,7 +63,7 @@ public: }; protected: - volatile ExecutionMode m_ExecMode; + std::atomic m_ExecMode; // This lock is used to avoid simultaneous requests to Suspend/Resume/Pause from // contending threads. @@ -71,7 +71,7 @@ protected: // Used to wake up the thread from sleeping when it's in a suspended state. Semaphore m_sem_Resume; - + // Used to synchronize inline changes from paused to suspended status. Semaphore m_sem_ChangingExecMode; @@ -79,7 +79,7 @@ protected: // Issue a Wait against this mutex for performing actions that require the thread // to be suspended. Mutex m_RunningLock; - + public: explicit SysThreadBase(); virtual ~SysThreadBase() throw(); @@ -99,7 +99,7 @@ public: bool IsClosing() const { - return !IsRunning() || (m_ExecMode <= ExecMode_Closed) || (m_ExecMode == ExecMode_Closing); + return !IsRunning() || (m_ExecMode <= ExecMode_Closed) || (m_ExecMode == ExecMode_Closing); } bool HasPendingStateChangeRequest() const @@ -107,7 +107,7 @@ public: return m_ExecMode >= ExecMode_Closing; } - ExecutionMode GetExecutionMode() const { return m_ExecMode; } + ExecutionMode GetExecutionMode() const { return m_ExecMode.load(); } Mutex& ExecutionModeMutex() { return m_ExecModeMutex; } virtual void Suspend( bool isBlocking = true ); @@ -172,10 +172,10 @@ protected: // true anytime between plugins being initialized and plugins being shutdown. Gets // set false when plugins are shutdown, the corethread is canceled, or when an error // occurs while trying to upload a new state into the VM. - volatile bool m_hasActiveMachine; + std::atomic m_hasActiveMachine; wxString m_elf_override; - + SSE_MXCSR m_mxcsr_saved; public: @@ -198,10 +198,10 @@ public: virtual void UploadStateCopy( const VmStateBuffer& copy ); virtual bool HasActiveMachine() const { return m_hasActiveMachine; } - + virtual const wxString& GetElfOverride() const { return m_elf_override; } virtual void SetElfOverride( const wxString& elf ); - + protected: void _reset_stuff_as_needed(); From 3a9bd90a3b9e43273c1c1efb618c2b992fe78d78 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 20:44:49 +0100 Subject: [PATCH 07/15] Gif: port code to std::atomic --- pcsx2/Gif_Unit.cpp | 4 ++-- pcsx2/Gif_Unit.h | 6 +++--- pcsx2/MTGS.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pcsx2/Gif_Unit.cpp b/pcsx2/Gif_Unit.cpp index d46a5fa4ec..a6fff5fb7a 100644 --- a/pcsx2/Gif_Unit.cpp +++ b/pcsx2/Gif_Unit.cpp @@ -118,14 +118,14 @@ void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) { } else { pxAssertDev(!gsPack.readAmount, "Gif Unit - gsPack.readAmount only valid for MTVU path 1!"); - AtomicExchangeAdd(gifUnit.gifPath[path].readAmount, gsPack.size); + gifUnit.gifPath[path].readAmount.fetch_add(gsPack.size); GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, gsPack.offset, gsPack.size, path); } } void Gif_AddBlankGSPacket(u32 size, GIF_PATH path) { //DevCon.WriteLn("Adding Blank Gif Packet [size=%x]", size); - AtomicExchangeAdd(gifUnit.gifPath[path].readAmount, size); + gifUnit.gifPath[path].readAmount.fetch_add(size); GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, ~0u, size, path); } diff --git a/pcsx2/Gif_Unit.h b/pcsx2/Gif_Unit.h index 8846b9d5a5..ecbaa54357 100644 --- a/pcsx2/Gif_Unit.h +++ b/pcsx2/Gif_Unit.h @@ -153,7 +153,7 @@ struct Gif_Path_MTVU { }; struct Gif_Path { - __aligned(4) volatile s32 readAmount; // Amount of data MTGS still needs to read + std::atomic readAmount; // Amount of data MTGS still needs to read u8* buffer; // Path packet buffer u32 buffSize; // Full size of buffer u32 buffLimit; // Cut off limit to wrap around @@ -195,7 +195,7 @@ struct Gif_Path { } bool isMTVU() const { return !idx && THREAD_VU1; } - s32 getReadAmount() { return AtomicRead(readAmount) + gsPack.readAmount; } + s32 getReadAmount() { return readAmount.load() + gsPack.readAmount; } bool hasDataRemaining() const { return curOffset < curSize; } bool isDone() const { return isMTVU() ? !mtvu.fakePackets : (!hasDataRemaining() && (state == GIF_PATH_IDLE || state == GIF_PATH_WAIT)); } @@ -380,7 +380,7 @@ struct Gif_Path { void FinishGSPacketMTVU() { if (1) { ScopedLock lock(mtvu.gsPackMutex); - AtomicExchangeAdd(readAmount, gsPack.size + gsPack.readAmount); + readAmount.fetch_add(gsPack.size + gsPack.readAmount); mtvu.gsPackQueue.push_back(gsPack); } gsPack.Reset(); diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 7e1b106c86..2898094e60 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -395,7 +395,7 @@ void SysMtgsThread::ExecuteTaskInThread() u32 offset = tag.data[0]; u32 size = tag.data[1]; if (offset != ~0u) GSgifTransfer((u32*)&path.buffer[offset], size/16); - AtomicExchangeSub(path.readAmount, size); + path.readAmount.fetch_sub(size); break; } @@ -409,7 +409,7 @@ void SysMtgsThread::ExecuteTaskInThread() Gif_Path& path = gifUnit.gifPath[GIF_PATH_1]; GS_Packet gsPack = path.GetGSPacketMTVU(); // Get vu1 program's xgkick packet(s) if (gsPack.size) GSgifTransfer((u32*)&path.buffer[gsPack.offset], gsPack.size/16); - AtomicExchangeSub(path.readAmount, gsPack.size + gsPack.readAmount); + path.readAmount.fetch_sub(gsPack.size + gsPack.readAmount); path.PopGSPacketMTVU(); // Should be done last, for proper Gif_MTGS_Wait() break; } From 410922a9434a1f6d9b3a06c31fddd4009e0eee4e Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 21:40:45 +0100 Subject: [PATCH 08/15] Deci2: port to std::atomic --- pcsx2/RDebug/deci2.h | 1 - pcsx2/RDebug/deci2_dbgp.cpp | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pcsx2/RDebug/deci2.h b/pcsx2/RDebug/deci2.h index 43fc5b46b4..dfcef220bd 100644 --- a/pcsx2/RDebug/deci2.h +++ b/pcsx2/RDebug/deci2.h @@ -52,7 +52,6 @@ struct DECI2_DBGP_BRK{ extern DECI2_DBGP_BRK ebrk[32], ibrk[32]; extern s32 ebrk_count, ibrk_count; -extern volatile long runStatus; extern s32 runCode, runCount; extern Threading::Semaphore* runEvent; diff --git a/pcsx2/RDebug/deci2_dbgp.cpp b/pcsx2/RDebug/deci2_dbgp.cpp index 22690a3253..85e7ed744a 100644 --- a/pcsx2/RDebug/deci2_dbgp.cpp +++ b/pcsx2/RDebug/deci2_dbgp.cpp @@ -24,6 +24,8 @@ using namespace Threading; using namespace R5900; +std::atomic runStatus; + struct DECI2_DBGP_HEADER{ DECI2_HEADER h; //+00 u16 id; //+08 @@ -358,7 +360,7 @@ void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char if (in->h.destination=='I') ; else{ - out->result = ( pcsx2_InterlockedExchange(&runStatus, STOP)==STOP ? + out->result = ( runStatus.exchange(STOP)==STOP ? 0x20 : 0x21 ); out->code=0xFF; Sleep(50); @@ -371,7 +373,7 @@ void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char if (in->h.destination=='I') ; else{ - pcsx2_InterlockedExchange(&runStatus, STOP); + runStatus = STOP; Sleep(100);//first get the run thread to Wait state runCount=in->count; runCode=in->code; @@ -390,7 +392,7 @@ void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char for (i=0, s=0; i<(int)run->argc; i++, argv++) s+=argv[i]; memcpy(PSM(0), argv, s); // threads_array[0].argstring = 0; - pcsx2_InterlockedExchange((volatile long*)&runStatus, (u32)STOP); + runStatus = STOP; Sleep(1000);//first get the run thread to Wait state runCount=0; runCode=0xFF; From 5a84a0d8d267fcc3afcc3d71b059e655e7339d49 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 21:53:24 +0100 Subject: [PATCH 09/15] MTGS: port to std::atomic Except the ring pointers m_ReadPos/m_WritePos because it requires memory access optimization --- pcsx2/GS.h | 10 +++++----- pcsx2/MTGS.cpp | 38 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 958c8e072d..80ed61c0cc 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -270,12 +270,12 @@ public: __aligned(4) uint m_ReadPos; // cur pos gs is reading from __aligned(4) uint m_WritePos; // cur pos ee thread is writing to - volatile bool m_RingBufferIsBusy; - volatile u32 m_SignalRingEnable; - volatile s32 m_SignalRingPosition; + std::atomic m_RingBufferIsBusy; + std::atomic m_SignalRingEnable; + std::atomic m_SignalRingPosition; - volatile s32 m_QueuedFrameCount; - volatile u32 m_VsyncSignalListener; + std::atomic m_QueuedFrameCount; + std::atomic m_VsyncSignalListener; Mutex m_mtx_RingBufferBusy; // Is obtained while processing ring-buffer data Mutex m_mtx_RingBufferBusy2; // This one gets released on semaXGkick waiting... diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 2898094e60..2c0fdbadfc 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -78,10 +78,10 @@ void SysMtgsThread::OnStart() m_packet_size = 0; m_packet_writepos = 0; - m_QueuedFrameCount = 0; + m_QueuedFrameCount = 0; m_VsyncSignalListener = false; - m_SignalRingEnable = 0; - m_SignalRingPosition= 0; + m_SignalRingEnable = false; + m_SignalRingPosition = 0; m_CopyDataTally = 0; @@ -155,13 +155,13 @@ void SysMtgsThread::PostVsyncStart() // in the ringbuffer. The queue limit is disabled when both FrameLimiting and Vsync are // disabled, since the queue can have perverse effects on framerate benchmarking. - // Edit: It's possible that MTGS is that much faster than the GS plugin that it creates so much lag, + // Edit: It's possible that MTGS is that much faster than the GS plugin that it creates so much lag, // a game becomes uncontrollable (software rendering for example). // For that reason it's better to have the limit always in place, at the cost of a few max FPS in benchmarks. // If those are needed back, it's better to increase the VsyncQueueSize via PCSX_vm.ini. // (The Xenosaga engine is known to run into this, due to it throwing bulks of data in one frame followed by 2 empty frames.) - if ((AtomicIncrement(m_QueuedFrameCount) < EmuConfig.GS.VsyncQueueSize) /*|| (!EmuConfig.GS.VsyncEnable && !EmuConfig.GS.FrameLimitEnable)*/) return; + if ((m_QueuedFrameCount.fetch_add(1) < EmuConfig.GS.VsyncQueueSize) /*|| (!EmuConfig.GS.VsyncEnable && !EmuConfig.GS.FrameLimitEnable)*/) return; m_VsyncSignalListener = true; //Console.WriteLn( Color_Blue, "(EEcore Sleep) Vsync\t\tringpos=0x%06x, writepos=0x%06x", volatize(m_ReadPos), m_WritePos ); @@ -238,7 +238,7 @@ void SysMtgsThread::OpenPlugin() GSsetGameCRC( ElfCRC, 0 ); } -struct RingBufferLock { +struct RingBufferLock { ScopedLock m_lock1; ScopedLock m_lock2; SysMtgsThread& m_mtgs; @@ -446,8 +446,8 @@ void SysMtgsThread::ExecuteTaskInThread() if( (GSopen2 == NULL) && (PADupdate != NULL) ) PADupdate(0); - AtomicDecrement( m_QueuedFrameCount ); - if (!!AtomicExchange(m_VsyncSignalListener, false)) + m_QueuedFrameCount.fetch_sub(1); + if (m_VsyncSignalListener.exchange(false)) m_sem_Vsync.Post(); busy.Release(); @@ -522,16 +522,16 @@ void SysMtgsThread::ExecuteTaskInThread() { pxAssert( m_WritePos == newringpos ); } - + m_ReadPos = newringpos; - if( m_SignalRingEnable != 0 ) + if( m_SignalRingEnable ) { // The EEcore has requested a signal after some amount of processed data. - if( AtomicExchangeSub( m_SignalRingPosition, ringposinc ) <= 0 ) + if( m_SignalRingPosition.fetch_sub( ringposinc ) <= 0 ) { // Make sure to post the signal after the m_ReadPos has been updated... - AtomicExchange( m_SignalRingEnable, 0 ); + m_SignalRingEnable = false; m_sem_OnRingReset.Post(); continue; } @@ -544,14 +544,14 @@ void SysMtgsThread::ExecuteTaskInThread() // won't sleep the eternity, even if SignalRingPosition didn't reach 0 for some reason. // Important: Need to unlock the MTGS busy signal PRIOR, so that EEcore SetEvent() calls // parallel to this handler aren't accidentally blocked. - if( AtomicExchange( m_SignalRingEnable, 0 ) != 0 ) + if( m_SignalRingEnable.exchange(false) ) { - //Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", AtomicExchange( m_SignalRingPosition, 0 ) ); - AtomicExchange( m_SignalRingPosition, 0 ); + //Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", m_SignalRingPosition.exchange(0) ) ); + m_SignalRingPosition = 0; m_sem_OnRingReset.Post(); } - if (!!AtomicExchange(m_VsyncSignalListener, false)) + if (m_VsyncSignalListener.exchange(false)) m_sem_Vsync.Post(); //Console.Warning( "(MTGS Thread) Nothing to do! ringpos=0x%06x", m_ReadPos ); @@ -617,7 +617,7 @@ void SysMtgsThread::WaitGS(bool syncRegs, bool weakWait, bool isMTVU) // hence it has been avoided... } } - + if (syncRegs) { ScopedLock lock(m_mtx_WaitGS); // Completely synchronize GS and MTGS register states. @@ -719,7 +719,7 @@ void SysMtgsThread::GenericStall( uint size ) //Console.WriteLn( Color_Blue, "(EEcore Sleep) PrepDataPacker \tringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", readpos, writepos, m_SignalRingPosition ); while(true) { - AtomicExchange( m_SignalRingEnable, 1 ); + m_SignalRingEnable = true; SetEvent(); m_sem_OnRingReset.WaitWithoutYield(); readpos = volatize(m_ReadPos); @@ -729,7 +729,7 @@ void SysMtgsThread::GenericStall( uint size ) freeroom = readpos - writepos; else freeroom = RingBufferSize - (writepos - readpos); - + if (freeroom > size) break; } From 8555a87380b63e637b3deebf9c61e08db65f4db1 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 22:02:24 +0100 Subject: [PATCH 10/15] GS.h: use std::atomic --- pcsx2/GS.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 80ed61c0cc..17a477a43b 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -291,8 +291,8 @@ public: // has more than one command in it when the thread is kicked. int m_CopyDataTally; - Semaphore m_sem_OpenDone; - volatile bool m_PluginOpened; + Semaphore m_sem_OpenDone; + std::atomic m_PluginOpened; // These vars maintain instance data for sending Data Packets. // Only one data packet can be constructed and uploaded at a time. From 40b1a3996a00eb540b26209c2d5d180c6af819bb Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 21:58:13 +0100 Subject: [PATCH 11/15] VU: port BaseVUmicroCPU to std::atomic --- pcsx2/VUmicro.h | 4 ++-- pcsx2/x86/microVU.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index f0943f6144..27cdeb1030 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -49,7 +49,7 @@ class BaseCpuProvider protected: // allocation counter for multiple calls to Reserve. Most implementations should utilize // this variable for sake of robustness. - u32 m_Reserved; + std::atomic m_Reserved; public: // this boolean indicates to some generic logging facilities if the VU's registers @@ -68,7 +68,7 @@ public: { try { if( m_Reserved != 0 ) - Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved ); + Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved.load() ); } DESTRUCTOR_CATCHALL } diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 68bb970ef1..8e61974523 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -297,22 +297,22 @@ void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(microVU0); } void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(microVU1); } void recMicroVU0::Reserve() { - if (AtomicExchange(m_Reserved, 1) == 0) + if (m_Reserved.exchange(1) == 0) mVUinit(microVU0, 0); } void recMicroVU1::Reserve() { - if (AtomicExchange(m_Reserved, 1) == 0) { + if (m_Reserved.exchange(1) == 0) { mVUinit(microVU1, 1); vu1Thread.Start(); } } void recMicroVU0::Shutdown() throw() { - if (AtomicExchange(m_Reserved, 0) == 1) + if (m_Reserved.exchange(0) == 1) mVUclose(microVU0); } void recMicroVU1::Shutdown() throw() { - if (AtomicExchange(m_Reserved, 0) == 1) { + if (m_Reserved.exchange(0) == 1) { vu1Thread.WaitVU(); mVUclose(microVU1); } From 3a4787dd98295011e7231c6a79be195b81ad9664 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 22:32:41 +0100 Subject: [PATCH 12/15] MTVU: partially port code to MTVU Remains volatize as MTGS and the ScopedLockBool stuff --- pcsx2/MTVU.cpp | 9 ++++----- pcsx2/MTVU.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index b77b37224f..e049ba3df7 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -47,7 +47,7 @@ static void MTVU_Unpack(void* data, VIFregisters& vifRegs) } // Called on Saving/Loading states... -void SaveStateBase::mtvuFreeze() +void SaveStateBase::mtvuFreeze() { FreezeTag("MTVU"); pxAssert(vu1Thread.IsDone()); @@ -142,7 +142,7 @@ void VU_Thread::ExecuteRingBuffer() break; } case MTVU_NULL_PACKET: - AtomicExchange(read_pos, 0); + read_pos = 0; break; jNO_DEFAULT; } @@ -187,7 +187,7 @@ void VU_Thread::ReserveSpace(s32 size) // Use this when reading read_pos from ee thread __fi s32 VU_Thread::GetReadPos() { - return AtomicRead(read_pos); + return read_pos.load(); } // Use this when reading write_pos from vu thread __fi s32 VU_Thread::GetWritePos() @@ -202,8 +202,7 @@ __fi u32* VU_Thread::GetWritePtr() __fi void VU_Thread::incReadPos(s32 offset) { // Offset in u32 sizes - s32 temp = (read_pos + offset) & buffer_mask; - AtomicExchange(read_pos, temp); + read_pos = (read_pos + offset) & buffer_mask; } __fi void VU_Thread::incWritePos() { // Adds write_offset diff --git a/pcsx2/MTVU.h b/pcsx2/MTVU.h index d404d75967..1a9bab8254 100644 --- a/pcsx2/MTVU.h +++ b/pcsx2/MTVU.h @@ -30,7 +30,7 @@ class VU_Thread : public pxThread { static const s32 buffer_size = (_1mb * 16) / sizeof(s32); static const u32 buffer_mask = buffer_size - 1; __aligned(4) u32 buffer[buffer_size]; - __aligned(4) volatile s32 read_pos; // Only modified by VU thread + __aligned(4) std::atomic read_pos; // Only modified by VU thread __aligned(4) volatile bool isBusy; // Is thread processing data? __aligned(4) s32 write_pos; // Only modified by EE thread __aligned(4) s32 write_offset; // Only modified by EE thread From ca8955daf3f2a9722539a7c1b1b80fd633944dbc Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 22:36:29 +0100 Subject: [PATCH 13/15] MTVU: port ScopedLockBool to std::atomic --- common/include/Utilities/Threading.h | 10 +++------- pcsx2/MTVU.h | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index b50fa2e2d8..6fa4de885d 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -402,15 +402,11 @@ namespace Threading // Note that the isLockedBool should only be used as an indicator for the locked status, // and not actually depended on for thread synchronization... - struct ScopedLockBool { + struct ScopedLockBool { ScopedLock m_lock; - volatile __aligned(4) bool& m_bool; + std::atomic& m_bool; -#ifdef __linux__ - ScopedLockBool(Mutex& mutexToLock, volatile bool& isLockedBool) -#else - ScopedLockBool(Mutex& mutexToLock, volatile __aligned(4) bool& isLockedBool) -#endif + ScopedLockBool(Mutex& mutexToLock, std::atomic& isLockedBool) : m_lock(mutexToLock), m_bool(isLockedBool) { m_bool = m_lock.IsLocked(); diff --git a/pcsx2/MTVU.h b/pcsx2/MTVU.h index 1a9bab8254..29cc1fcf36 100644 --- a/pcsx2/MTVU.h +++ b/pcsx2/MTVU.h @@ -31,7 +31,7 @@ class VU_Thread : public pxThread { static const u32 buffer_mask = buffer_size - 1; __aligned(4) u32 buffer[buffer_size]; __aligned(4) std::atomic read_pos; // Only modified by VU thread - __aligned(4) volatile bool isBusy; // Is thread processing data? + __aligned(4) std::atomic isBusy; // Is thread processing data? __aligned(4) s32 write_pos; // Only modified by EE thread __aligned(4) s32 write_offset; // Only modified by EE thread __aligned(4) Mutex mtxBusy; From 5ca92ecd67d95a15baaf93eb80a1be594a514779 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 22:14:29 +0100 Subject: [PATCH 14/15] Common: port code to std::atomic --- common/include/Utilities/General.h | 2 +- common/include/Utilities/PersistentThread.h | 8 ++++---- common/src/Utilities/Mutex.cpp | 6 +++--- common/src/Utilities/ThreadTools.cpp | 6 +++--- common/src/Utilities/wxHelpers.cpp | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index f2182e5fad..074157fd72 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -111,7 +111,7 @@ protected: class BaseDeletableObject : public virtual IDeletableObject { protected: - volatile vol_t m_IsBeingDeleted; + std::atomic m_IsBeingDeleted; public: BaseDeletableObject(); diff --git a/common/include/Utilities/PersistentThread.h b/common/include/Utilities/PersistentThread.h index 247020dbd8..491930855f 100644 --- a/common/include/Utilities/PersistentThread.h +++ b/common/include/Utilities/PersistentThread.h @@ -103,8 +103,8 @@ namespace Threading MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally. Mutex m_mtx_ThreadName; - volatile vol_t m_detached; // a boolean value which indicates if the m_thread handle is valid - volatile s32 m_running; // set true by Start(), and set false by Cancel(), Block(), etc. + std::atomic m_detached; // a boolean value which indicates if the m_thread handle is valid + std::atomic m_running; // set true by Start(), and set false by Cancel(), Block(), etc. // exception handle, set non-NULL if the thread terminated with an exception // Use RethrowException() to re-throw the exception using its original exception type. @@ -243,8 +243,8 @@ namespace Threading class BaseTaskThread : public pxThread { protected: - volatile bool m_Done; - volatile bool m_TaskPending; + std::atomic m_Done; + std::atomic m_TaskPending; Semaphore m_post_TaskComplete; Mutex m_lock_TaskComplete; diff --git a/common/src/Utilities/Mutex.cpp b/common/src/Utilities/Mutex.cpp index 19d0735c16..9822b3bb21 100644 --- a/common/src/Utilities/Mutex.cpp +++ b/common/src/Utilities/Mutex.cpp @@ -23,7 +23,7 @@ namespace Threading { - static vol_t _attr_refcount = 0; + static std::atomic _attr_refcount(0); static pthread_mutexattr_t _attr_recursive; } @@ -120,7 +120,7 @@ Threading::Mutex::~Mutex() throw() Threading::MutexRecursive::MutexRecursive() : Mutex( false ) { - if( _InterlockedIncrement( &_attr_refcount ) == 1 ) + if( _attr_refcount.fetch_add(1) == 1 ) { if( 0 != pthread_mutexattr_init( &_attr_recursive ) ) throw Exception::OutOfMemory(L"Recursive mutexing attributes"); @@ -134,7 +134,7 @@ Threading::MutexRecursive::MutexRecursive() : Mutex( false ) Threading::MutexRecursive::~MutexRecursive() throw() { - if( _InterlockedDecrement( &_attr_refcount ) == 0 ) + if( _attr_refcount.fetch_sub(1) == 0 ) pthread_mutexattr_destroy( &_attr_recursive ); } diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 324abca580..7c9820a210 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -291,7 +291,7 @@ bool Threading::pxThread::Detach() { AffinityAssert_DisallowFromSelf(pxDiagSpot); - if( _InterlockedExchange( &m_detached, true ) ) return false; + if( m_detached.exchange(true) ) return false; pthread_detach( m_thread ); return true; } @@ -386,7 +386,7 @@ bool Threading::pxThread::IsSelf() const bool Threading::pxThread::IsRunning() const { - return !!m_running; + return m_running; } void Threading::pxThread::AddListener( EventListener_Thread& evt ) @@ -669,7 +669,7 @@ void Threading::pxThread::OnCleanupInThread() m_native_handle = 0; m_native_id = 0; - + m_evtsrc_OnDelete.Dispatch( 0 ); } diff --git a/common/src/Utilities/wxHelpers.cpp b/common/src/Utilities/wxHelpers.cpp index dbb2bd1f0b..21242e6a37 100644 --- a/common/src/Utilities/wxHelpers.cpp +++ b/common/src/Utilities/wxHelpers.cpp @@ -49,7 +49,7 @@ pxDialogCreationFlags pxDialogFlags() // bool BaseDeletableObject::MarkForDeletion() { - return !_InterlockedExchange( &m_IsBeingDeleted, true ); + return !m_IsBeingDeleted.exchange(true); } void BaseDeletableObject::DeleteSelf() From 610bf8a27751589679df9ce788557e28bd85d674 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 22 Feb 2016 22:23:09 +0100 Subject: [PATCH 15/15] Common: delete most of the deprecated atomic API --- common/include/Utilities/Threading.h | 12 +----------- common/include/intrin_x86.h | 25 ------------------------- common/src/Utilities/ThreadTools.cpp | 25 ------------------------- 3 files changed, 1 insertion(+), 61 deletions(-) diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 6fa4de885d..26967e5a8a 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -158,7 +158,7 @@ namespace Threading // For use in spin/wait loops. extern void SpinWait(); - + // Use prior to committing data to another thread extern void StoreFence(); @@ -181,16 +181,6 @@ namespace Threading extern s32 AtomicRead( volatile s32& Target ); extern u32 AtomicExchange( volatile u32& Target, u32 value ); extern s32 AtomicExchange( volatile s32& Target, s32 value ); - extern u32 AtomicExchangeAdd( volatile u32& Target, u32 value ); - extern s32 AtomicExchangeAdd( volatile s32& Target, s32 value ); - extern s32 AtomicExchangeSub( volatile s32& Target, s32 value ); - extern u32 AtomicIncrement( volatile u32& Target ); - extern s32 AtomicIncrement( volatile s32& Target ); - extern u32 AtomicDecrement( volatile u32& Target ); - extern s32 AtomicDecrement( volatile s32& Target ); - - extern bool AtomicBitTestAndReset( volatile u32& bitset, u8 bit ); - extern bool AtomicBitTestAndReset( volatile s32& bitset, u8 bit ); // pthread Cond is an evil api that is not suited for Pcsx2 needs. // Let's not use it. Use mutexes and semaphores instead to create waits. (Air) diff --git a/common/include/intrin_x86.h b/common/include/intrin_x86.h index 9665dd141c..6b83a2928e 100644 --- a/common/include/intrin_x86.h +++ b/common/include/intrin_x86.h @@ -54,16 +54,6 @@ /*** Atomic operations ***/ -static __inline__ __attribute__((always_inline)) s32 _InterlockedCompareExchange(volatile s32 * const Destination, const s32 Exchange, const s32 Comperand) -{ - return __sync_val_compare_and_swap(Destination, Comperand, Exchange); -} - -static __inline__ __attribute__((always_inline)) s64 _InterlockedCompareExchange64(volatile s64 * const Destination, const s64 Exchange, const s64 Comperand) -{ - return __sync_val_compare_and_swap(Destination, Comperand, Exchange); -} - static __inline__ __attribute__((always_inline)) s32 _InterlockedExchange(volatile s32 * const Target, const s32 Value) { /* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */ @@ -78,21 +68,6 @@ static __inline__ __attribute__((always_inline)) s64 _InterlockedExchange64(vola return __sync_lock_test_and_set(Target, Value); } -static __inline__ __attribute__((always_inline)) s32 _InterlockedExchangeAdd(volatile s32 * const Addend, const s32 Value) -{ - return __sync_fetch_and_add(Addend, Value); -} - -static __inline__ __attribute__((always_inline)) s32 _InterlockedDecrement(volatile s32 * const lpAddend) -{ - return _InterlockedExchangeAdd(lpAddend, -1) - 1; -} - -static __inline__ __attribute__((always_inline)) s32 _InterlockedIncrement(volatile s32 * const lpAddend) -{ - return _InterlockedExchangeAdd(lpAddend, 1) + 1; -} - /*** System information ***/ static __inline__ __attribute__((always_inline)) void __cpuid(int CPUInfo[], const int InfoType) { diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 7c9820a210..417dbe05d5 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -803,31 +803,6 @@ __fi s32 Threading::AtomicExchange( volatile s32& Target, s32 value ) { return _InterlockedExchange( (volatile vol_t*)&Target, value ); } -__fi u32 Threading::AtomicExchangeAdd( volatile u32& Target, u32 value ) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, value ); -} -__fi s32 Threading::AtomicExchangeAdd( volatile s32& Target, s32 value ) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, value ); -} - -__fi s32 Threading::AtomicExchangeSub( volatile s32& Target, s32 value ) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, -value ); -} - -__fi u32 Threading::AtomicIncrement( volatile u32& Target ) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, 1 ); -} -__fi s32 Threading::AtomicIncrement( volatile s32& Target) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, 1 ); -} - -__fi u32 Threading::AtomicDecrement( volatile u32& Target ) { - return _InterlockedExchangeAdd( (volatile vol_t*)&Target, -1 ); -} -__fi s32 Threading::AtomicDecrement(volatile s32& Target) { - return _InterlockedExchangeAdd((volatile vol_t*)&Target, -1); -} - // -------------------------------------------------------------------------------------- // BaseThreadError // --------------------------------------------------------------------------------------