Common/Threading: Move a bunch of unnecessary wrappers to gui

This commit is contained in:
Connor McLaughlin 2022-05-09 20:28:57 +10:00 committed by refractionpcsx2
parent 65e956a01c
commit e5716922a3
19 changed files with 274 additions and 340 deletions

View File

@ -20,7 +20,6 @@ target_sources(common PRIVATE
FastFormatString.cpp
FastJmp.cpp
FileSystem.cpp
Mutex.cpp
Misc.cpp
MD5Digest.cpp
PathUtils.cpp
@ -33,7 +32,6 @@ target_sources(common PRIVATE
StringHelpers.cpp
StringUtil.cpp
Timer.cpp
ThreadTools.cpp
WindowInfo.cpp
emitter/bmi.cpp
emitter/cpudetect.cpp

View File

@ -15,6 +15,7 @@
#if defined(__APPLE__)
#include <sched.h>
#include <unistd.h>
#include <mach/mach_init.h>
#include <mach/thread_act.h>
@ -32,6 +33,11 @@ __forceinline void Threading::Sleep(int ms)
usleep(1000 * ms);
}
__forceinline void Threading::Timeslice()
{
sched_yield();
}
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()

View File

@ -23,6 +23,7 @@
#include "common/Dependencies.h" // _ macro
#include "common/Threading.h"
#include "common/General.h"
#include "common/StringHelpers.h"
// for lack of a better place...
Fnptr_OutOfMemory pxDoOutOfMemory = NULL;

View File

@ -55,6 +55,11 @@ __forceinline void Threading::Sleep(int ms)
usleep(1000 * ms);
}
__forceinline void Threading::Timeslice()
{
sched_yield();
}
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()

View File

@ -14,11 +14,14 @@
*/
#include "common/Threading.h"
#include "common/Assertions.h"
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#endif
#include <limits>
// --------------------------------------------------------------------------------------
// Semaphore Implementations
// --------------------------------------------------------------------------------------
@ -168,4 +171,4 @@ bool Threading::KernelSemaphore::TryWait()
#endif
}
#endif
#endif

View File

@ -1,26 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Threading.h"
void Threading::pxTestCancel()
{
pthread_testcancel();
}
__fi void Threading::Timeslice()
{
sched_yield();
}

View File

@ -15,21 +15,15 @@
#pragma once
#include <wx/datetime.h>
#ifdef _WIN32
// thanks I hate it.
#include <wx/filefn.h>
#define HAVE_MODE_T
#endif
#include <semaphore.h>
#include <errno.h> // EBUSY
#include <pthread.h>
#ifdef __APPLE__
#include <mach/semaphore.h>
#endif
#include "common/Pcsx2Defs.h"
#include "common/TraceLog.h"
#include "common/General.h"
#if defined(__APPLE__)
#include <mach/semaphore.h>
#elif !defined(_WIN32)
#include <semaphore.h>
#endif
#include <atomic>
// --------------------------------------------------------------------------------------
@ -52,12 +46,11 @@
namespace Threading
{
class ThreadHandle;
class pxThread;
class RwMutex;
extern void pxTestCancel();
extern void YieldToMain();
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
@ -65,17 +58,6 @@ namespace Threading
/// Set the name of the current thread
extern void SetNameOfCurrentThread(const char* name);
extern const wxTimeSpan def_yieldgui_interval;
} // namespace Threading
namespace Threading
{
// --------------------------------------------------------------------------------------
// Platform Specific External APIs
// --------------------------------------------------------------------------------------
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
// Releases a timeslice to other threads.
extern void Timeslice();
@ -129,44 +111,6 @@ namespace Threading
#endif
};
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange.
//
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
// it later.
//
class NonblockingMutex
{
protected:
std::atomic_flag val;
public:
NonblockingMutex() { val.clear(); }
virtual ~NonblockingMutex() = default;
bool TryAcquire() noexcept
{
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()
{
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
return false;
}
void Release()
{
val.clear();
}
};
/// A semaphore that may not have a fast userspace path
/// (Used in other semaphore-based algorithms where the semaphore is just used for its thread sleep/wake ability)
class KernelSemaphore
@ -261,92 +205,4 @@ namespace Threading
/// Should be called by the worker thread if it restarts after dying
void Reset();
};
class Mutex
{
protected:
pthread_mutex_t m_mutex;
public:
Mutex();
virtual ~Mutex();
virtual bool IsRecursive() const { return false; }
void Recreate();
bool RecreateIfLocked();
void Detach();
void Acquire();
bool Acquire(const wxTimeSpan& timeout);
bool TryAcquire();
void Release();
void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan& timeout);
void Wait();
void WaitWithSpin();
bool Wait(const wxTimeSpan& timeout);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
protected:
// empty constructor used by MutexLockRecursive
Mutex(bool) {}
};
class MutexRecursive : public Mutex
{
public:
MutexRecursive();
virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; }
};
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// Helper class for using Mutexes. Using this class provides an exception-safe (and
// generally clean) method of locking code inside a function or conditional block. The lock
// will be automatically released on any return or exit from the function.
//
// Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales:
//
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
// this class needs a const hack to allow those accessors to be const (which is typically
// *very* important).
//
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
// scope exits, by any means. Only via manual calls to Release or Acquire does that
// change, and typically those are only used in very special circumstances of their own.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
protected:
Mutex* m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock();
explicit ScopedLock(const Mutex* locker = NULL);
explicit ScopedLock(const Mutex& locker);
void AssignAndLock(const Mutex& locker);
void AssignAndLock(const Mutex* locker);
void Assign(const Mutex& locker);
void Assign(const Mutex* locker);
void Release();
void Acquire();
bool IsLocked() const { return m_IsLocked; }
protected:
// Special constructor used by ScopedTryLock
ScopedLock(const Mutex& locker, bool isTryLock);
};
} // namespace Threading

View File

@ -24,6 +24,11 @@ __fi void Threading::Sleep(int ms)
::Sleep(ms);
}
__fi void Threading::Timeslice()
{
::Sleep(0);
}
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption.
__fi void Threading::SpinWait()

View File

@ -98,9 +98,7 @@
<ClCompile Include="Windows\WinMisc.cpp" />
<ClCompile Include="Windows\WinThreads.cpp" />
<ClCompile Include="Misc.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="Semaphore.cpp" />
<ClCompile Include="ThreadTools.cpp" />
<ClCompile Include="emitter\bmi.cpp" />
<ClCompile Include="emitter\cpudetect.cpp" />
<ClCompile Include="emitter\fpu.cpp" />

View File

@ -52,9 +52,6 @@
<ClCompile Include="Misc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PathUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -76,9 +73,6 @@
<ClCompile Include="StringHelpers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ThreadTools.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VirtualMemory.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -29,6 +29,7 @@
*/
#pragma once
#include <vector>
namespace x86Emitter
{

View File

@ -26,6 +26,7 @@
//------------------------------------------------------------------
#include "common/emitter/legacy_internal.h"
#include "common/Console.h"
emitterT void ModRM(uint mod, uint reg, uint rm)
{

View File

@ -16,6 +16,8 @@
#pragma once
#include "common/Threading.h"
#include "common/Assertions.h"
#include "common/Pcsx2Defs.h"
static const uint iREGCNT_XMM = 16;
static const uint iREGCNT_GPR = 16;

View File

@ -1119,6 +1119,7 @@ set(pcsx2GuiSources
gui/MainFrame.cpp
gui/MainMenuClicks.cpp
gui/MessageBoxes.cpp
gui/Mutex.cpp
gui/MSWstuff.cpp
gui/Panels/BaseApplicableConfigPanel.cpp
gui/Panels/BiosSelectorPanel.cpp
@ -1195,7 +1196,6 @@ set(pcsx2GuiHeaders
gui/pxStaticText.h
gui/RecentIsoList.h
gui/Saveslots.h
gui/ScopedPtrMT.h
gui/SysThreads.h
gui/ThreadingDialogs.h
gui/ThreadingDialogs.cpp

View File

@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Threading.h"
#include "PersistentThread.h"
namespace Threading
{

View File

@ -17,7 +17,16 @@
#include "common/Threading.h"
#include "common/EventSource.h"
#include "ScopedPtrMT.h"
#include "common/Console.h"
#include "common/TraceLog.h"
#include <wx/datetime.h>
#include <pthread.h>
#ifdef __APPLE__
#include <mach/semaphore.h>
#else
#include <semaphore.h>
#endif
#undef Yield // release the burden of windows.h global namespace spam.
@ -113,12 +122,227 @@ namespace Exception
namespace Threading
{
extern void pxTestCancel();
extern void YieldToMain();
extern const wxTimeSpan def_yieldgui_interval;
extern pxThread* pxGetCurrentThread();
extern wxString pxGetCurrentThreadName();
extern bool _WaitGui_RecursionGuard(const wxChar* name);
extern bool AllowDeletions();
class Mutex
{
protected:
pthread_mutex_t m_mutex;
public:
Mutex();
virtual ~Mutex();
virtual bool IsRecursive() const { return false; }
void Recreate();
bool RecreateIfLocked();
void Detach();
void Acquire();
bool Acquire(const wxTimeSpan& timeout);
bool TryAcquire();
void Release();
void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan& timeout);
void Wait();
void WaitWithSpin();
bool Wait(const wxTimeSpan& timeout);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
protected:
// empty constructor used by MutexLockRecursive
Mutex(bool) {}
};
class MutexRecursive : public Mutex
{
public:
MutexRecursive();
virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; }
};
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// Helper class for using Mutexes. Using this class provides an exception-safe (and
// generally clean) method of locking code inside a function or conditional block. The lock
// will be automatically released on any return or exit from the function.
//
// Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales:
//
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
// this class needs a const hack to allow those accessors to be const (which is typically
// *very* important).
//
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
// scope exits, by any means. Only via manual calls to Release or Acquire does that
// change, and typically those are only used in very special circumstances of their own.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
protected:
Mutex* m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock();
explicit ScopedLock(const Mutex* locker = NULL);
explicit ScopedLock(const Mutex& locker);
void AssignAndLock(const Mutex& locker);
void AssignAndLock(const Mutex* locker);
void Assign(const Mutex& locker);
void Assign(const Mutex* locker);
void Release();
void Acquire();
bool IsLocked() const { return m_IsLocked; }
protected:
// Special constructor used by ScopedTryLock
ScopedLock(const Mutex& locker, bool isTryLock);
};
// --------------------------------------------------------------------------------------
// ScopedPtrMT
// --------------------------------------------------------------------------------------
template <typename T>
class ScopedPtrMT
{
DeclareNoncopyableObject(ScopedPtrMT);
protected:
std::atomic<T*> m_ptr;
Threading::Mutex m_mtx;
public:
typedef T element_type;
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
{
m_ptr = ptr;
}
~ScopedPtrMT() { _Delete_unlocked(); }
ScopedPtrMT& Reassign(T* ptr = nullptr)
{
T* doh = m_ptr.exchange(ptr);
if (ptr != doh)
delete doh;
return *this;
}
ScopedPtrMT& Delete() noexcept
{
ScopedLock lock(m_mtx);
_Delete_unlocked();
}
// Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method)
T* DetachPtr()
{
ScopedLock lock(m_mtx);
return m_ptr.exchange(nullptr);
}
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
// has no object in management.
T* GetPtr() const
{
return m_ptr;
}
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;
}
// ----------------------------------------------------------------------------
// ScopedPtrMT Operators
// ----------------------------------------------------------------------------
// I've decided to use the ATL's approach to pointer validity tests, opposed to
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
// allow the T* implicit casting.
bool operator!() const noexcept
{
return m_ptr.load() == nullptr;
}
// Equality
bool operator==(T* pT) const noexcept
{
return m_ptr == pT;
}
// Inequality
bool operator!=(T* pT) const noexcept
{
return !operator==(pT);
}
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer.
ScopedPtrMT& operator=(T* src)
{
return Reassign(src);
}
#if 0
operator T*() const
{
return m_ptr;
}
// Dereference operator, returns a handle to the managed pointer.
// Generates a debug assertion if the object is nullptr!
T& operator*() const
{
pxAssert(m_ptr != nullptr);
return *m_ptr;
}
T* operator->() const
{
pxAssert(m_ptr != nullptr);
return m_ptr;
}
#endif
protected:
void _Delete_unlocked() noexcept
{
delete m_ptr.exchange(nullptr);
}
};
// ----------------------------------------------------------------------------------------
// RecursionGuard - Basic protection against function recursion
// ----------------------------------------------------------------------------------------

View File

@ -1,140 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Threading.h"
using Threading::ScopedLock;
// --------------------------------------------------------------------------------------
// ScopedPtrMT
// --------------------------------------------------------------------------------------
template <typename T>
class ScopedPtrMT
{
DeclareNoncopyableObject(ScopedPtrMT);
protected:
std::atomic<T*> m_ptr;
Threading::Mutex m_mtx;
public:
typedef T element_type;
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
{
m_ptr = ptr;
}
~ScopedPtrMT() { _Delete_unlocked(); }
ScopedPtrMT& Reassign(T* ptr = nullptr)
{
T* doh = m_ptr.exchange(ptr);
if (ptr != doh)
delete doh;
return *this;
}
ScopedPtrMT& Delete() noexcept
{
ScopedLock lock(m_mtx);
_Delete_unlocked();
}
// Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method)
T* DetachPtr()
{
ScopedLock lock(m_mtx);
return m_ptr.exchange(nullptr);
}
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
// has no object in management.
T* GetPtr() const
{
return m_ptr;
}
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;
}
// ----------------------------------------------------------------------------
// ScopedPtrMT Operators
// ----------------------------------------------------------------------------
// I've decided to use the ATL's approach to pointer validity tests, opposed to
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
// allow the T* implicit casting.
bool operator!() const noexcept
{
return m_ptr.load() == nullptr;
}
// Equality
bool operator==(T* pT) const noexcept
{
return m_ptr == pT;
}
// Inequality
bool operator!=(T* pT) const noexcept
{
return !operator==(pT);
}
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer.
ScopedPtrMT& operator=(T* src)
{
return Reassign(src);
}
#if 0
operator T*() const
{
return m_ptr;
}
// Dereference operator, returns a handle to the managed pointer.
// Generates a debug assertion if the object is nullptr!
T& operator*() const
{
pxAssert(m_ptr != nullptr);
return *m_ptr;
}
T* operator->() const
{
pxAssert(m_ptr != nullptr);
return m_ptr;
}
#endif
protected:
void _Delete_unlocked() noexcept
{
delete m_ptr.exchange(nullptr);
}
};

View File

@ -354,6 +354,7 @@
<ClCompile Include="gui\Dialogs\McdConfigDialog.cpp" />
<ClCompile Include="gui\DriveList.cpp" />
<ClCompile Include="gui\IniInterface.cpp" />
<ClCompile Include="gui\Mutex.cpp" />
<ClCompile Include="gui\Panels\MemoryCardListView.cpp" />
<ClCompile Include="gui\PersistentThread.cpp" />
<ClCompile Include="gui\pxCheckBox.cpp" />
@ -818,7 +819,6 @@
<ClInclude Include="gui\Debugger\DebuggerLists.h" />
<ClInclude Include="gui\Debugger\DisassemblyDialog.h" />
<ClInclude Include="gui\Panels\MemoryCardPanels.h" />
<ClInclude Include="gui\ScopedPtrMT.h" />
<ClInclude Include="gui\ThreadingDialogs.h" />
<ClInclude Include="gui\wxAppWithHelpers.h" />
<ClInclude Include="gui\wxSettingsInterface.h" />

View File

@ -1769,7 +1769,12 @@
<ClCompile Include="GS\Renderers\DX12\GSDevice12.cpp">
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
</ClCompile>
<ClCompile Include="gui\PersistentThread.cpp" />
<ClCompile Include="gui\Mutex.cpp">
<Filter>AppHost</Filter>
</ClCompile>
<ClCompile Include="gui\PersistentThread.cpp">
<Filter>AppHost</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2946,8 +2951,9 @@
<ClInclude Include="GS\Renderers\DX12\GSTexture12.h">
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
</ClInclude>
<ClInclude Include="gui\ScopedPtrMT.h" />
<ClInclude Include="gui\PersistentThread.h" />
<ClInclude Include="gui\PersistentThread.h">
<Filter>AppHost</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="windows\wxResources.rc">