From 9a8a411a0ba5f68c93f35b9c82138c12db299f94 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 6 Aug 2021 13:23:14 -0700 Subject: [PATCH] [development] removal of unused and low stakes code related to Cry-threading (#2896) Removal highlights include: - File indexer (used CryThread<>) linked to long gone asset browser - Producer/consumer queues from CryMT - set/vector/CLocklessPointerQueue containers also from CryMT - Cry interlocked linked list and _InterlockedCompareExchange128 - CryThread type - SAtomicVar types - CryAutoSet type - Various unused lock types -- AutoLockModify -- AutoLockRead -- CryOptionalAutoLock -- CryReadModifyLock -- CryRWLock -- ReadLock -- ReadLockCond -- WriteAfterReadLock - Misc. unused functions -- CryInterLockedAdd (not to be confused with CryInterlockedAdd, using a lower case "locked") -- CryInterlockedExchange64 (which was only defined for unix platforms) -- SpinLock -- JobSpinLock -- AtomicAdd -- JobAtomicAdd Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 19 - .../PerforcePlugin/PerforceSourceControl.cpp | 2 +- Code/Editor/Util/IndexedFiles.cpp | 202 ------ Code/Editor/Util/IndexedFiles.h | 176 ----- Code/Editor/editor_lib_files.cmake | 2 - Code/Legacy/CryCommon/AndroidSpecific.h | 11 - Code/Legacy/CryCommon/CryThread.h | 638 ------------------ .../Legacy/CryCommon/CryThreadImpl_pthreads.h | 191 ------ Code/Legacy/CryCommon/CryThreadImpl_windows.h | 250 ------- Code/Legacy/CryCommon/CryThread_pthreads.h | 233 ------- Code/Legacy/CryCommon/CryThread_windows.h | 78 --- Code/Legacy/CryCommon/Linux_Win32Wrapper.h | 3 - Code/Legacy/CryCommon/MultiThread.h | 318 --------- .../Legacy/CryCommon/MultiThread_Containers.h | 315 --------- Code/Legacy/CryCommon/WinBase.cpp | 19 - Code/Legacy/CryCommon/iOSSpecific.h | 4 - 16 files changed, 1 insertion(+), 2460 deletions(-) delete mode 100644 Code/Editor/Util/IndexedFiles.cpp delete mode 100644 Code/Editor/Util/IndexedFiles.h diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index efeb7cdd19..cd1dd4fe47 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -127,7 +127,6 @@ AZ_POP_DISABLE_WARNING #include "Util/AutoDirectoryRestoreFileDialog.h" #include "Util/EditorAutoLevelLoadTest.h" -#include "Util/IndexedFiles.h" #include "AboutDialog.h" #include @@ -1715,18 +1714,6 @@ BOOL CCryEditApp::InitInstance() if (IsInRegularEditorMode()) { - CIndexedFiles::Create(); - - if (gEnv->pConsole->GetCVar("ed_indexfiles")->GetIVal()) - { - Log("Started game resource files indexing..."); - CIndexedFiles::StartFileIndexing(); - } - else - { - Log("Game resource files indexing is disabled."); - } - // QuickAccessBar creation should be before m_pMainWnd->SetFocus(), // since it receives the focus at creation time. It brakes MainFrame key accelerators. m_pQuickAccessBar = new CQuickAccessBar; @@ -2163,12 +2150,6 @@ int CCryEditApp::ExitInstance(int exitCode) } } - if (IsInRegularEditorMode()) - { - CIndexedFiles::AbortFileIndexing(); - CIndexedFiles::Destroy(); - } - if (GetIEditor() && !GetIEditor()->IsInMatEditMode()) { //Nobody seems to know in what case that kind of exit can happen so instrumented to see if it happens at all diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp index aec613b8df..581f9a576d 100644 --- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp +++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp @@ -56,7 +56,7 @@ void CPerforceSourceControl::ShowSettings() void CPerforceSourceControl::SetSourceControlState(SourceControlState state) { - AUTO_LOCK(g_cPerforceValues); + CryAutoLock lock(g_cPerforceValues); switch (state) { diff --git a/Code/Editor/Util/IndexedFiles.cpp b/Code/Editor/Util/IndexedFiles.cpp deleted file mode 100644 index ae777abb49..0000000000 --- a/Code/Editor/Util/IndexedFiles.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -// Description : Tagged files database for 'SmartFileOpen' dialog - -#include "EditorDefs.h" - -#include "IndexedFiles.h" - -volatile TIntAtomic CIndexedFiles::s_bIndexingDone; -CIndexedFiles* CIndexedFiles::s_pIndexedFiles = nullptr; - -bool CIndexedFiles::m_startedFileIndexing = false; - -void CIndexedFiles::Initialize(const QString& path, IFileUtil::ScanDirectoryUpdateCallBack updateCB) -{ - m_files.clear(); - m_pathToIndex.clear(); - m_tags.clear(); - m_rootPath = path; - - bool anyFiles = CFileUtil::ScanDirectory(path, "*.*", m_files, true, true, updateCB); - - if (anyFiles == false) - { - m_files.clear(); - return; - } - - if (updateCB) - { - updateCB("Parsing & tagging..."); - } - - for (int i = 0; i < m_files.size(); ++i) - { - m_pathToIndex[m_files[i].filename] = i; - } - - PrepareTagTable(); - - InvokeUpdateCallbacks(); -} - -void CIndexedFiles::AddFile(const IFileUtil::FileDesc& path) -{ - assert(m_pathToIndex.find(path.filename) == m_pathToIndex.end()); - m_files.push_back(path); - m_pathToIndex[path.filename] = m_files.size() - 1; - QStringList tags; - GetTags(tags, path.filename); - for (int k = 0; k < tags.size(); ++k) - { - m_tags[tags[k]].insert(m_files.size() - 1); - } -} - -void CIndexedFiles::RemoveFile(const QString& path) -{ - if (m_pathToIndex.find(path) == m_pathToIndex.end()) - { - return; - } - std::map::iterator itr = m_pathToIndex.find(path); - int index = itr->second; - m_pathToIndex.erase(itr); - m_files.erase(m_files.begin() + index); - QStringList tags; - GetTags(tags, path); - for (int k = 0; k < tags.size(); ++k) - { - m_tags[tags[k]].erase(index); - } -} - -void CIndexedFiles::Refresh(const QString& path, bool recursive) -{ - IFileUtil::FileArray files; - bool anyFiles = CFileUtil::ScanDirectory(m_rootPath, Path::Make(path, "*.*"), files, recursive, recursive ? true : false); - - if (anyFiles == false) - { - return; - } - - for (int i = 0; i < files.size(); ++i) - { - if (m_pathToIndex.find(files[i].filename) == m_pathToIndex.end()) - { - AddFile(files[i]); - } - } - - InvokeUpdateCallbacks(); -} - -void CIndexedFiles::GetFilesWithTags(IFileUtil::FileArray& files, const QStringList& tags) const -{ - files.clear(); - if (tags.empty()) - { - return; - } - int_set candidates; - TagTable::const_iterator i; - // Gets candidate files from the first tag. - for (i = m_tags.begin(); i != m_tags.end(); ++i) - { - if (i->first.startsWith(tags[0])) - { - candidates.insert(i->second.begin(), i->second.end()); - } - } - // Reduces the candidates further using additional tags, if any. - for (int k = 1; k < tags.size(); ++k) - { - // Gathers the filter set. - int_set filter; - for (i = m_tags.begin(); i != m_tags.end(); ++i) - { - if (i->first.startsWith(tags[k])) - { - filter.insert(i->second.begin(), i->second.end()); - } - } - - // Filters the candidates using it. - for (int_set::iterator m = candidates.begin(); m != candidates.end(); ) - { - if (filter.find(*m) == filter.end()) - { - int_set::iterator target = m; - ++m; - candidates.erase(target); - } - else - { - ++m; - } - } - } - // Outputs the result. - files.reserve(candidates.size()); - for (int_set::const_iterator m = candidates.begin(); m != candidates.end(); ++m) - { - files.push_back(m_files[*m]); - } -} - -void CIndexedFiles::GetTags(QStringList& tags, const QString& path) const -{ - tags = path.split(QRegularExpression(QStringLiteral(R"([\\/.])")), Qt::SkipEmptyParts); -} - -void CIndexedFiles::GetTagsOfPrefix(QStringList& tags, const QString& prefix) const -{ - tags.clear(); - TagTable::const_iterator i; - for (i = m_tags.begin(); i != m_tags.end(); ++i) - { - if (i->first.startsWith(prefix)) - { - tags.push_back(i->first); - } - } -} - -void CIndexedFiles::PrepareTagTable() -{ - QStringList tags; - for (int i = 0; i < m_files.size(); ++i) - { - GetTags(tags, m_files[i].filename); - for (int k = 0; k < tags.size(); ++k) - { - m_tags[tags[k]].insert(i); - } - } -} - -void CIndexedFiles::AddUpdateCallback(std::function updateCallback) -{ - CryAutoLock lock(m_updateCallbackMutex); - - m_updateCallbacks.push_back(updateCallback); -} - -void CIndexedFiles::InvokeUpdateCallbacks() -{ - CryAutoLock lock(m_updateCallbackMutex); - - for (auto updateCallback : m_updateCallbacks) - { - updateCallback(); - } -} diff --git a/Code/Editor/Util/IndexedFiles.h b/Code/Editor/Util/IndexedFiles.h deleted file mode 100644 index e23c0ea827..0000000000 --- a/Code/Editor/Util/IndexedFiles.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -// Description : Tagged files database for 'SmartFileOpen' dialog -// -// Notice : Refer SmartFileOpenDialog h - - -#ifndef CRYINCLUDE_EDITOR_UTIL_INDEXEDFILES_H -#define CRYINCLUDE_EDITOR_UTIL_INDEXEDFILES_H -#pragma once - - -#include "FileUtil.h" -#include - -class CIndexedFiles -{ - friend class CFileIndexingThread; -public: - static CIndexedFiles& GetDB() - { - if (!s_pIndexedFiles) - { - assert(!"CIndexedFiles not created! Make sure you use CIndexedFiles::GetDB() after CIndexedFiles::StartFileIndexing() is called."); - } - assert(s_pIndexedFiles); - return *s_pIndexedFiles; - } - - static bool HasFileIndexingDone() - { return s_bIndexingDone > 0; } - - static void Create() - { - assert(!s_pIndexedFiles); - s_pIndexedFiles = new CIndexedFiles; - } - - static void Destroy() - { - SAFE_DELETE(s_pIndexedFiles); - } - - static void StartFileIndexing() - { - assert(s_bIndexingDone == 0); - assert(s_pIndexedFiles); - - if (!s_pIndexedFiles) - { - return; - } - - GetFileIndexingThread().Start(-1, "FileIndexing"); - m_startedFileIndexing = true; - } - - static void AbortFileIndexing() - { - if (!m_startedFileIndexing) - { - return; - } - - if (HasFileIndexingDone() == false) - { - GetFileIndexingThread().Abort(); - } - m_startedFileIndexing = false; - } - - static void RegisterCallback(std::function callback) - { - assert(s_pIndexedFiles); - if (!s_pIndexedFiles) - { - return; - } - - s_pIndexedFiles->AddUpdateCallback(callback); - } - -public: - void Initialize(const QString& path, IFileUtil::ScanDirectoryUpdateCallBack updateCB = nullptr); - - // Adds a new file to the database. - void AddFile(const IFileUtil::FileDesc& path); - // Removes a no-longer-existing file from the database. - void RemoveFile(const QString& path); - // Refreshes this database for the subdirectory. - void Refresh(const QString& path, bool recursive = true); - - void GetFilesWithTags(IFileUtil::FileArray& files, const QStringList& tags) const; - - //! This method returns all the tags which start with a given prefix. - //! It is useful for the tag auto-completion. - void GetTagsOfPrefix(QStringList& tags, const QString& prefix) const; - - uint32 GetTotalCount() const - { return (uint32)m_files.size(); } - -private: - static bool m_startedFileIndexing; - - std::vector > m_updateCallbacks; - IFileUtil::FileArray m_files; - std::map m_pathToIndex; - typedef std::set > int_set; - typedef std::map > TagTable; - TagTable m_tags; - QString m_rootPath; - - void GetTags(QStringList& tags, const QString& path) const; - void PrepareTagTable(); - - CryMutex m_updateCallbackMutex; - - void AddUpdateCallback(std::function updateCallback); - void InvokeUpdateCallbacks(); - - // A done flag for the background file indexing - static volatile TIntAtomic s_bIndexingDone; - // A thread for the background file indexing - class CFileIndexingThread - : public CryThread - { - public: - virtual void Run() - { - CIndexedFiles::GetDB().Initialize("@assets@", CallBack); - CryInterlockedAdd(CIndexedFiles::s_bIndexingDone.Addr(), 1); - } - - CFileIndexingThread() - : m_abort(false) {} - - void Abort() - { - m_abort = true; - WaitForThread(); - } - - virtual ~CFileIndexingThread() - { - Abort(); - } - private: - bool m_abort; - static bool CallBack([[maybe_unused]] const QString& msg) - { - if (CIndexedFiles::GetFileIndexingThread().m_abort) - { - return false; - } - return true; - } - }; - - static CFileIndexingThread& GetFileIndexingThread() - { - static CFileIndexingThread s_fileIndexingThread; - - return s_fileIndexingThread; - } - - // A global database for tagged files - static CIndexedFiles* s_pIndexedFiles; -}; -#endif // CRYINCLUDE_EDITOR_UTIL_INDEXEDFILES_H diff --git a/Code/Editor/editor_lib_files.cmake b/Code/Editor/editor_lib_files.cmake index 386b495faa..d59edfe6a8 100644 --- a/Code/Editor/editor_lib_files.cmake +++ b/Code/Editor/editor_lib_files.cmake @@ -724,8 +724,6 @@ set(FILES Util/GuidUtil.cpp Util/GuidUtil.h Util/IObservable.h - Util/IndexedFiles.cpp - Util/IndexedFiles.h Util/KDTree.cpp Util/Mailer.h Util/NamedData.cpp diff --git a/Code/Legacy/CryCommon/AndroidSpecific.h b/Code/Legacy/CryCommon/AndroidSpecific.h index d4832172fc..0cb4a6786c 100644 --- a/Code/Legacy/CryCommon/AndroidSpecific.h +++ b/Code/Legacy/CryCommon/AndroidSpecific.h @@ -30,17 +30,6 @@ #define MOBILE #endif -#if (defined(__clang__) && NDK_REV_MAJOR >= 14) || (defined(_CPU_ARM) && defined(PLATFORM_64BIT)) - // The version of clang that NDK r14+ ships with is seemingly generating different (for better or worse) code for the atomic operations - // used in the LocklessLinkedList. In either case, this is causing deadlocks in the job system and crashes from memory stomps in - // the bucket allocator. By defining INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED it will disable the Cry job system as well as - // change the implementation of the LocklessLinkedList to use a mutex in it's operations instead, essentially use the same behaviour - // as iOS. While not ideal to use this as a band-aid on the problem, it does fix it with a negligible performance impact. - // - // Additionally, arm64 processors do not provide a cmpxchg16b (or equivalent) instruction required for _InterlockedCompareExchange128 - #define INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED -#endif - // Force all allocations to be aligned to TARGET_DEFAULT_ALIGN. // This is because malloc on Android 32 bit returns memory that is not aligned // to what some structs/classes need. diff --git a/Code/Legacy/CryCommon/CryThread.h b/Code/Legacy/CryCommon/CryThread.h index 691616651a..5929bed352 100644 --- a/Code/Legacy/CryCommon/CryThread.h +++ b/Code/Legacy/CryCommon/CryThread.h @@ -78,77 +78,6 @@ public: ~CryAutoLock() { m_pLock->Unlock(); } }; -////////////////////////////////////////////////////////////////////////// -// -// CryOptionalAutoLock implements a helper class to automatically -// lock critical section (if needed) in constructor and release on destructor. -// -////////////////////////////////////////////////////////////////////////// -template -class CryOptionalAutoLock -{ -private: - LockClass* m_Lock; - bool m_bLockAcquired; - - CryOptionalAutoLock(); - CryOptionalAutoLock(const CryOptionalAutoLock&); - CryOptionalAutoLock& operator = (const CryOptionalAutoLock&); - -public: - CryOptionalAutoLock(LockClass& Lock, bool acquireLock) - : m_Lock(&Lock) - , m_bLockAcquired(false) - { - if (acquireLock) - { - Acquire(); - } - } - ~CryOptionalAutoLock() - { - Release(); - } - void Release() - { - if (m_bLockAcquired) - { - m_Lock->Unlock(); - m_bLockAcquired = false; - } - } - void Acquire() - { - if (!m_bLockAcquired) - { - m_Lock->Lock(); - m_bLockAcquired = true; - } - } -}; - -////////////////////////////////////////////////////////////////////////// -// -// CryAutoSet implements a helper class to automatically -// set and reset value in constructor and release on destructor. -// -////////////////////////////////////////////////////////////////////////// -template -class CryAutoSet -{ -private: - ValueClass* m_pValue; - - CryAutoSet(); - CryAutoSet(const CryAutoSet&); - CryAutoSet& operator = (const CryAutoSet&); - -public: - CryAutoSet(ValueClass& value) - : m_pValue(&value) { *m_pValue = (ValueClass)1; } - ~CryAutoSet() { *m_pValue = (ValueClass)0; } -}; - ////////////////////////////////////////////////////////////////////////// // // Auto critical section is the most commonly used type of auto lock. @@ -156,10 +85,6 @@ public: ////////////////////////////////////////////////////////////////////////// typedef CryAutoLock CryAutoCriticalSection; -#define AUTO_LOCK_T(Type, lock) PREFAST_SUPPRESS_WARNING(6246); CryAutoLock __AutoLock(lock) -#define AUTO_LOCK(lock) AUTO_LOCK_T(CryCriticalSection, lock) -#define AUTO_LOCK_CS(csLock) CryAutoCriticalSection __AL__##csLock(csLock) - ///////////////////////////////////////////////////////////////////////////// // // Threads. @@ -235,14 +160,6 @@ struct CryThreadInfo template class CrySimpleThread; -// Standard thread class. -// -// The class provides a lock (mutex) and an associated condition variable. If -// you don't need the lock, then you should used CrySimpleThread instead of -// CryThread. -template -class CryThread; - /////////////////////////////////////////////////////////////////////////////// // Include architecture specific code. #if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS @@ -265,560 +182,5 @@ class CryThread; typedef CryLockT CryMutex; #endif // !_CRYTHREAD_CONDLOCK_GLITCH -// The the architecture specific code does not define a class CryRWLock, then -// a default implementation is provided here. -#if !defined _CRYTHREAD_HAVE_RWLOCK && !defined _CRYTHREAD_CONDLOCK_GLITCH -class CryRWLock -{ - CryCriticalSection m_lockExclusiveAccess; - CryCriticalSection m_lockSharedAccessComplete; - CryConditionVariable m_condSharedAccessComplete; - - int m_nSharedAccessCount; - int m_nCompletedSharedAccessCount; - bool m_bExclusiveAccess; - - CryRWLock(const CryRWLock&); - CryRWLock& operator= (const CryRWLock&); - - void AdjustSharedAccessCount() - { - m_nSharedAccessCount -= m_nCompletedSharedAccessCount; - m_nCompletedSharedAccessCount = 0; - } - -public: - CryRWLock() - : m_nSharedAccessCount(0) - , m_nCompletedSharedAccessCount(0) - , m_bExclusiveAccess(false) - { } - - void RLock() - { - m_lockExclusiveAccess.Lock(); - if (++m_nSharedAccessCount == INT_MAX) - { - m_lockSharedAccessComplete.Lock(); - AdjustSharedAccessCount(); - m_lockSharedAccessComplete.Unlock(); - } - m_lockExclusiveAccess.Unlock(); - } - - bool TryRLock() - { - if (!m_lockExclusiveAccess.TryLock()) - { - return false; - } - if (++m_nSharedAccessCount == INT_MAX) - { - m_lockSharedAccessComplete.Lock(); - AdjustSharedAccessCount(); - m_lockSharedAccessComplete.Unlock(); - } - m_lockExclusiveAccess.Unlock(); - return true; - } - - void RUnlock() - { - Unlock(); - } - - void WLock() - { - m_lockExclusiveAccess.Lock(); - m_lockSharedAccessComplete.Lock(); - assert(!m_bExclusiveAccess); - AdjustSharedAccessCount(); - if (m_nSharedAccessCount > 0) - { - m_nCompletedSharedAccessCount -= m_nSharedAccessCount; - do - { - m_condSharedAccessComplete.Wait(m_lockSharedAccessComplete); - } - while (m_nCompletedSharedAccessCount < 0); - m_nSharedAccessCount = 0; - } - m_bExclusiveAccess = true; - } - - bool TryWLock() - { - if (!m_lockExclusiveAccess.TryLock()) - { - return false; - } - if (!m_lockSharedAccessComplete.TryLock()) - { - m_lockExclusiveAccess.Unlock(); - return false; - } - assert(!m_bExclusiveAccess); - AdjustSharedAccessCount(); - if (m_nSharedAccessCount > 0) - { - m_lockSharedAccessComplete.Unlock(); - m_lockExclusiveAccess.Unlock(); - return false; - } - else - { - m_bExclusiveAccess = true; - } - return true; - } - - void WUnlock() - { - Unlock(); - } - - void Unlock() - { - if (!m_bExclusiveAccess) - { - m_lockSharedAccessComplete.Lock(); - if (++m_nCompletedSharedAccessCount == 0) - { - m_condSharedAccessComplete.NotifySingle(); - } - m_lockSharedAccessComplete.Unlock(); - } - else - { - m_bExclusiveAccess = false; - m_lockSharedAccessComplete.Unlock(); - m_lockExclusiveAccess.Unlock(); - } - } -}; -#endif // !defined _CRYTHREAD_HAVE_RWLOCK - -// Thread class. -// -// CryThread is an extension of CrySimpleThread providing a lock (mutex) and a -// condition variable per instance. -template -class CryThread - : public CrySimpleThread -{ - CryMutex m_Lock; - CryConditionVariable m_Cond; - - CryThread(const CryThread&); - void operator = (const CryThread&); - -public: - CryThread() { } - void Lock() { m_Lock.Lock(); } - bool TryLock() { return m_Lock.TryLock(); } - void Unlock() { m_Lock.Unlock(); } - void Wait() { m_Cond.Wait(m_Lock); } - // Timed wait on the associated condition. - // - // The 'milliseconds' parameter specifies the relative timeout in - // milliseconds. The method returns true if a notification was received and - // false if the specified timeout expired without receiving a notification. - // - // UNIX note: the method will _not_ return if the calling thread receives a - // signal. Instead the call is re-started with the _original_ timeout - // value. This misfeature may be fixed in the future. - bool TimedWait(uint32 milliseconds) - { - return m_Cond.TimedWait(m_Lock, milliseconds); - } - void Notify() { m_Cond.Notify(); } - void NotifySingle() { m_Cond.NotifySingle(); } - CryMutex& GetLock() { return m_Lock; } -}; - -////////////////////////////////////////////////////////////////////////// -// -// Sync primitive for multiple reads and exclusive locking change access -// -// Desc: -// Useful in case if you have rarely modified object that needs -// to be read quite often from different threads but still -// need to be exclusively modified sometimes -// Debug functionality: -// Can be used for debug-only lock calls, which verify that no -// simultaneous access is attempted. -// Use the bDebug argument of LockRead or LockModify, -// or use the DEBUG_READLOCK or DEBUG_MODIFYLOCK macros. -// There is no overhead in release builds, if you use the macros, -// and the lock definition is inside #ifdef _DEBUG. -////////////////////////////////////////////////////////////////////////// - -class CryReadModifyLock -{ -public: - CryReadModifyLock() - : m_modifyCount(0) - , m_readCount(0) - { - SetDebugLocked(false); - } - - bool LockRead(bool bTry = false, cstr strDebug = 0, bool bDebug = false) const - { - if (!WriteLock(bTry, bDebug, strDebug)) // wait until write unlocked - { - return false; - } - CryInterlockedIncrement(&m_readCount); // increment read counter - m_writeLock.Unlock(); - return true; - } - void UnlockRead() const - { - SetDebugLocked(false); - const int counter = CryInterlockedDecrement(&m_readCount); // release read - assert(counter >= 0); - if (m_writeLock.TryLock()) - { - m_writeLock.Unlock(); - } - else - if (counter == 0 && m_modifyCount) - { - m_ReadReleased.Set(); // signal the final read released - } - } - bool LockModify(bool bTry = false, cstr strDebug = 0, bool bDebug = false) const - { - if (!WriteLock(bTry, bDebug, strDebug)) - { - return false; - } - CryInterlockedIncrement(&m_modifyCount); // increment write counter (counter is for nested cases) - while (m_readCount) - { - m_ReadReleased.Wait(); // wait for all threads finish read operation - } - return true; - } - void UnlockModify() const - { - SetDebugLocked(false); -#if !defined(NDEBUG) - int counter = -#endif - CryInterlockedDecrement(&m_modifyCount); // decrement write counter - assert(counter >= 0); - m_writeLock.Unlock(); // release exclusive lock - } - -protected: - mutable volatile int m_readCount; - mutable volatile int m_modifyCount; - mutable CryEvent m_ReadReleased; - mutable CryCriticalSection m_writeLock; - mutable bool m_debugLocked; - mutable const char* m_debugLockStr; - - void SetDebugLocked([[maybe_unused]] bool b, [[maybe_unused]] const char* str = 0) const - { -#ifdef _DEBUG - m_debugLocked = b; - m_debugLockStr = str; -#endif - } - - bool WriteLock(bool bTry, [[maybe_unused]] bool bDebug, [[maybe_unused]] const char* strDebug) const - { - if (!m_writeLock.TryLock()) - { -#ifdef _DEBUG - assert(!m_debugLocked); - assert(!bDebug); -#endif - if (bTry) - { - return false; - } - m_writeLock.Lock(); - } -#ifdef _DEBUG - if (!m_readCount && !m_modifyCount) // not yet locked - { - SetDebugLocked(bDebug, strDebug); - } -#endif - return true; - } -}; - -// Auto-locking classes. -template -class AutoLockRead -{ -protected: - const T& m_lock; -public: - AutoLockRead(const T& lock, cstr strDebug = 0) - : m_lock(lock) { m_lock.LockRead(bDEBUG, strDebug, bDEBUG); } - ~AutoLockRead() - { m_lock.UnlockRead(); } -}; - -template -class AutoLockModify -{ -protected: - const T& m_lock; -public: - AutoLockModify(const T& lock, cstr strDebug = 0) - : m_lock(lock) { m_lock.LockModify(bDEBUG, strDebug, bDEBUG); } - ~AutoLockModify() - { m_lock.UnlockModify(); } -}; - -#define AUTO_READLOCK(p) PREFAST_SUPPRESS_WARNING(6246) AutoLockRead AZ_JOIN(__readlock, __LINE__)(p, __FUNC__) -#define AUTO_READLOCK_PROT(p) PREFAST_SUPPRESS_WARNING(6246) AutoLockRead AZ_JOIN(__readlock_prot, __LINE__)(p, __FUNC__) -#define AUTO_MODIFYLOCK(p) PREFAST_SUPPRESS_WARNING(6246) AutoLockModify AZ_JOIN(__modifylock, __LINE__)(p, __FUNC__) - -#if defined(_DEBUG) - #define DEBUG_READLOCK(p) AutoLockRead AZ_JOIN(__readlock, __LINE__)(p, __FUNC__) - #define DEBUG_MODIFYLOCK(p) AutoLockModify AZ_JOIN(__modifylock, __LINE__)(p, __FUNC__) -#else - #define DEBUG_READLOCK(p) - #define DEBUG_MODIFYLOCK(p) -#endif - -// producer consumer queue implementations, but here instead of MultiThread_Container.h -// since they requiere platform specific code, and including windows.h in a very common -// header file leads to all kinds of problems -namespace CryMT -{ - ////////////////////////////////////////////////////////////////////////// - // Producer/Consumer Queue for 1 to 1 thread communication - // Realized with only volatile variables and memory barriers - // *warning* this producer/consumer queue is only thread safe in a 1 to 1 situation - // and doesn't provide any yields or similar to prevent spinning - ////////////////////////////////////////////////////////////////////////// - template - class SingleProducerSingleConsumerQueue - : public CryMT::detail::SingleProducerSingleConsumerQueueBase - { - public: - SingleProducerSingleConsumerQueue(); - ~SingleProducerSingleConsumerQueue(); - - void Init(size_t nSize); - - void Push(const T& rObj); - void Pop(T* pResult); - uint32 Size() { return (m_nProducerIndex - m_nComsumerIndex); } - uint32 BufferSize() { return m_nBufferSize; } - uint32 FreeCount() { return (m_nBufferSize - (m_nProducerIndex - m_nComsumerIndex)); } - - private: - T* m_arrBuffer; - uint32 m_nBufferSize; - - volatile uint32 m_nProducerIndex _ALIGN(16); - volatile uint32 m_nComsumerIndex _ALIGN(16); - } _ALIGN(128); - - /////////////////////////////////////////////////////////////////////////////// - template - inline SingleProducerSingleConsumerQueue::SingleProducerSingleConsumerQueue() - : m_arrBuffer(NULL) - , m_nBufferSize(0) - , m_nProducerIndex(0) - , m_nComsumerIndex(0) - {} - - /////////////////////////////////////////////////////////////////////////////// - template - inline SingleProducerSingleConsumerQueue::~SingleProducerSingleConsumerQueue() - { - CryModuleMemalignFree(m_arrBuffer); - m_nBufferSize = 0; - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void SingleProducerSingleConsumerQueue::Init(size_t nSize) - { - assert(m_arrBuffer == NULL); - assert(m_nBufferSize == 0); - assert((nSize & (nSize - 1)) == 0); - - m_arrBuffer = alias_cast(CryModuleMemalign(nSize * sizeof(T), 16)); - m_nBufferSize = nSize; - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void SingleProducerSingleConsumerQueue::Push(const T& rObj) - { - assert(m_arrBuffer != NULL); - assert(m_nBufferSize != 0); - SingleProducerSingleConsumerQueueBase::Push((void*)&rObj, m_nProducerIndex, m_nComsumerIndex, m_nBufferSize, m_arrBuffer, sizeof(T)); - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void SingleProducerSingleConsumerQueue::Pop(T* pResult) - { - assert(m_arrBuffer != NULL); - assert(m_nBufferSize != 0); - SingleProducerSingleConsumerQueueBase::Pop(pResult, m_nProducerIndex, m_nComsumerIndex, m_nBufferSize, m_arrBuffer, sizeof(T)); - } - - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // Producer/Consumer Queue for N to 1 thread communication - // lockfree implemenation, to copy with multiple producers, - // a internal producer refcount is managed, the queue is empty - // as soon as there are no more producers and no new elements - ////////////////////////////////////////////////////////////////////////// - template - class N_ProducerSingleConsumerQueue - : public CryMT::detail::N_ProducerSingleConsumerQueueBase - { - public: - N_ProducerSingleConsumerQueue(); - ~N_ProducerSingleConsumerQueue(); - - void Init(size_t nSize); - - void Push(const T& rObj); - bool Pop(T* pResult); - - // needs to be called before using, assumes that there is at least one producer - // so the first one doesn't need to call AddProducer, but he has to deregister itself - void SetRunningState(); - - // to correctly track when the queue is empty(and no new jobs will be added), refcount the producer - void AddProducer(); - void RemoveProducer(); - - uint32 Size() { return (m_nProducerIndex - m_nComsumerIndex); } - uint32 BufferSize() { return m_nBufferSize; } - uint32 FreeCount() { return (m_nBufferSize - (m_nProducerIndex - m_nComsumerIndex)); } - - private: - T* m_arrBuffer; - volatile uint32* m_arrStates; - uint32 m_nBufferSize; - - volatile uint32 m_nProducerIndex; - volatile uint32 m_nComsumerIndex; - volatile uint32 m_nRunning; - volatile uint32 m_nProducerCount; - } _ALIGN(128); - - /////////////////////////////////////////////////////////////////////////////// - template - inline N_ProducerSingleConsumerQueue::N_ProducerSingleConsumerQueue() - : m_arrBuffer(NULL) - , m_arrStates(NULL) - , m_nBufferSize(0) - , m_nProducerIndex(0) - , m_nComsumerIndex(0) - , m_nRunning(0) - , m_nProducerCount(0) - {} - - /////////////////////////////////////////////////////////////////////////////// - template - inline N_ProducerSingleConsumerQueue::~N_ProducerSingleConsumerQueue() - { - CryModuleMemalignFree(m_arrBuffer); - CryModuleMemalignFree((void*)m_arrStates); - m_nBufferSize = 0; - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void N_ProducerSingleConsumerQueue::Init(size_t nSize) - { - assert(m_arrBuffer == NULL); - assert(m_arrStates == NULL); - assert(m_nBufferSize == 0); - assert((nSize & (nSize - 1)) == 0); - - m_arrBuffer = alias_cast(CryModuleMemalign(nSize * sizeof(T), 16)); - m_arrStates = alias_cast(CryModuleMemalign(nSize * sizeof(uint32), 16)); - memset((void*)m_arrStates, 0, sizeof(uint32) * nSize); - m_nBufferSize = nSize; - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void N_ProducerSingleConsumerQueue::SetRunningState() - { -#if !defined(_RELEASE) - if (m_nRunning == 1) - { - __debugbreak(); - } -#endif - m_nRunning = 1; - m_nProducerCount = 1; - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void N_ProducerSingleConsumerQueue::AddProducer() - { - assert(m_arrBuffer != NULL); - assert(m_arrStates != NULL); - assert(m_nBufferSize != 0); -#if !defined(_RELEASE) - if (m_nRunning == 0) - { - __debugbreak(); - } -#endif - CryInterlockedIncrement((volatile int*)&m_nProducerCount); - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void N_ProducerSingleConsumerQueue::RemoveProducer() - { - assert(m_arrBuffer != NULL); - assert(m_arrStates != NULL); - assert(m_nBufferSize != 0); -#if !defined(_RELEASE) - if (m_nRunning == 0) - { - __debugbreak(); - } -#endif - if (CryInterlockedDecrement((volatile int*)&m_nProducerCount) == 0) - { - m_nRunning = 0; - } - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline void N_ProducerSingleConsumerQueue::Push(const T& rObj) - { - assert(m_arrBuffer != NULL); - assert(m_arrStates != NULL); - assert(m_nBufferSize != 0); - CryMT::detail::N_ProducerSingleConsumerQueueBase::Push((void*)&rObj, m_nProducerIndex, m_nComsumerIndex, m_nRunning, m_arrBuffer, m_nBufferSize, sizeof(T), m_arrStates); - } - - /////////////////////////////////////////////////////////////////////////////// - template - inline bool N_ProducerSingleConsumerQueue::Pop(T* pResult) - { - assert(m_arrBuffer != NULL); - assert(m_arrStates != NULL); - assert(m_nBufferSize != 0); - return CryMT::detail::N_ProducerSingleConsumerQueueBase::Pop(pResult, m_nProducerIndex, m_nComsumerIndex, m_nRunning, m_arrBuffer, m_nBufferSize, sizeof(T), m_arrStates); - } -} //namespace CryMT - // Include all multithreading containers. #include "MultiThread_Containers.h" diff --git a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h index 895cbde524..c94d4fca90 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h @@ -107,195 +107,4 @@ void* CryCreateCriticalSection() return (void*) new TCritSecType; } -#if AZ_TRAIT_SKIP_CRYINTERLOCKED -#elif defined(INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED) -////////////////////////////////////////////////////////////////////////// -void CryInterlockedPushEntrySList(SLockFreeSingleLinkedListHeader& list, SLockFreeSingleLinkedListEntry& element) -{ - AZStd::lock_guard lock(list.mutex); - - element.pNext = list.pNext; - list.pNext = &element; -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list) -{ - AZStd::lock_guard lock(list.mutex); - - SLockFreeSingleLinkedListEntry* returnValue = list.pNext; - if (list.pNext) - { - list.pNext = list.pNext->pNext; - } - return returnValue; -} - -////////////////////////////////////////////////////////////////////////// -void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list) -{ - AZStd::lock_guard lock(list.mutex); - - list.pNext = NULL; -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list) -{ - AZStd::lock_guard lock(list.mutex); - - SLockFreeSingleLinkedListEntry* returnValue = list.pNext; - list.pNext = nullptr; - return returnValue; -} - -#elif defined(LINUX32) -////////////////////////////////////////////////////////////////////////// -// Implementation for Linux32 with gcc using uint64 -////////////////////////////////////////////////////////////////////////// -void CryInterlockedPushEntrySList(SLockFreeSingleLinkedListHeader& list, SLockFreeSingleLinkedListEntry& element) -{ - uint32 curSetting[2]; - uint32 newSetting[2]; - uint32 newPointer = (uint32) & element; - do - { - curSetting[0] = (uint32)list.pNext; - curSetting[1] = list.salt; - element.pNext = (SLockFreeSingleLinkedListEntry*)curSetting[0]; - newSetting[0] = newPointer; // new pointer - newSetting[1] = curSetting[1] + 1; // new salt - } - while (false == __sync_bool_compare_and_swap((volatile uint64*)&list.pNext, *(uint64*)&curSetting[0], *(uint64*)&newSetting[0])); -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list) -{ - uint32 curSetting[2]; - uint32 newSetting[2]; - do - { - curSetting[1] = list.salt; - curSetting[0] = (uint32)list.pNext; - if (curSetting[0] == 0) - { - return NULL; - } - newSetting[0] = *(uint32*)curSetting[0]; // new pointer - newSetting[1] = curSetting[1] + 1; // new salt - } - while (false == __sync_bool_compare_and_swap((volatile uint64*)&list.pNext, *(uint64*)&curSetting[0], *(uint64*)&newSetting[0])); - return (void*)curSetting[0]; -} - -////////////////////////////////////////////////////////////////////////// -void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list) -{ - list.salt = 0; - list.pNext = NULL; -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list) -{ - uint32 curSetting[2]; - uint32 newSetting[2]; - uint32 newSalt; - uint32 newPointer; - do - { - curSetting[1] = list.salt; - curSetting[0] = (uint32)list.pNext; - if (curSetting[0] == 0) - { - return NULL; - } - newSetting[0] = 0; - newSetting[1] = curSetting[1] + 1; - } - while (false == __sync_bool_compare_and_swap((volatile uint64*)&list.pNext, *(uint64*)&curSetting[0], *(uint64*)&newSetting[0])); - return (void*)curSetting[0]; -} -#else -// This implementation get's used on multiple platforms that support uint128 compare and swap. - -////////////////////////////////////////////////////////////////////////// -// LINUX64 Implementation of Lockless Single Linked List -////////////////////////////////////////////////////////////////////////// -typedef __uint128_t uint128; - -////////////////////////////////////////////////////////////////////////// -// Implementation for Linux64 with gcc using __int128_t -////////////////////////////////////////////////////////////////////////// -void CryInterlockedPushEntrySList(SLockFreeSingleLinkedListHeader& list, SLockFreeSingleLinkedListEntry& element) -{ - uint64 curSetting[2]; - uint64 newSetting[2]; - uint64 newPointer = (uint64) & element; - do - { - curSetting[0] = (uint64)list.pNext; - curSetting[1] = list.salt; - element.pNext = (SLockFreeSingleLinkedListEntry*)curSetting[0]; - newSetting[0] = newPointer; // new pointer - newSetting[1] = curSetting[1] + 1; // new salt - } - // while (false == __sync_bool_compare_and_swap( (volatile uint128*)&list.pNext,*(uint128*)&curSetting[0],*(uint128*)&newSetting[0] )); - while (0 == _InterlockedCompareExchange128((volatile int64*)&list.pNext, (int64)newSetting[1], (int64)newSetting[0], (int64*)&curSetting[0])); -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list) -{ - uint64 curSetting[2]; - uint64 newSetting[2]; - do - { - curSetting[1] = list.salt; - curSetting[0] = (uint64)list.pNext; - if (curSetting[0] == 0) - { - return NULL; - } - newSetting[0] = *(uint64*)curSetting[0]; // new pointer - newSetting[1] = curSetting[1] + 1; // new salt - } - //while (false == __sync_bool_compare_and_swap( (volatile uint128*)&list.pNext,*(uint128*)&curSetting[0],*(uint128*)&newSetting[0] )); - while (0 == _InterlockedCompareExchange128((volatile int64*)&list.pNext, (int64)newSetting[1], (int64)newSetting[0], (int64*)&curSetting[0])); - return (void*)curSetting[0]; -} - -////////////////////////////////////////////////////////////////////////// -void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list) -{ - list.salt = 0; - list.pNext = NULL; -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list) -{ - uint64 curSetting[2]; - uint64 newSetting[2]; - uint64 newSalt; - uint64 newPointer; - do - { - curSetting[1] = list.salt; - curSetting[0] = (uint64)list.pNext; - if (curSetting[0] == 0) - { - return NULL; - } - newSetting[0] = 0; - newSetting[1] = curSetting[1] + 1; - } - // while (false == __sync_bool_compare_and_swap( (volatile uint128*)&list.pNext,*(uint128*)&curSetting[0],*(uint128*)&newSetting[0] )); - while (0 == _InterlockedCompareExchange128((volatile int64*)&list.pNext, (int64)newSetting[1], (int64)newSetting[0], (int64*)&curSetting[0])); - return (void*)curSetting[0]; -} -////////////////////////////////////////////////////////////////////////// -#endif - #endif // CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H diff --git a/Code/Legacy/CryCommon/CryThreadImpl_windows.h b/Code/Legacy/CryCommon/CryThreadImpl_windows.h index 0451258aac..5cf970414d 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_windows.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_windows.h @@ -303,78 +303,6 @@ void CryFastSemaphore::Release() } } -////////////////////////////////////////////////////////////////////////// -CryRWLock::CryRWLock() -{ - STATIC_ASSERT(sizeof(m_Lock) == sizeof(PSRWLOCK), "RWLock-pointer has invalid size"); - InitializeSRWLock(reinterpret_cast(&m_Lock)); -} - -////////////////////////////////////////////////////////////////////////// -CryRWLock::~CryRWLock() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::RLock() -{ - AcquireSRWLockShared(reinterpret_cast(&m_Lock)); -} - -////////////////////////////////////////////////////////////////////////// -#if defined(_CRYTHREAD_WANT_TRY_RWLOCK) -bool CryRWLock::TryRLock() -{ - return TryAcquireSRWLockShared(reinterpret_cast(&m_Lock)) != 0; -} -#endif - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::RUnlock() -{ - ReleaseSRWLockShared(reinterpret_cast(&m_Lock)); -} - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::WLock() -{ - AcquireSRWLockExclusive(reinterpret_cast(&m_Lock)); -} - -////////////////////////////////////////////////////////////////////////// -#if defined(_CRYTHREAD_WANT_TRY_RWLOCK) -bool CryRWLock::TryWLock() -{ - return TryAcquireSRWLockExclusive(reinterpret_cast(&m_Lock)) != 0; -} -#endif - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::WUnlock() -{ - ReleaseSRWLockExclusive(reinterpret_cast(&m_Lock)); -} - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::Lock() -{ - WLock(); -} - -////////////////////////////////////////////////////////////////////////// -#if defined(_CRYTHREAD_WANT_TRY_RWLOCK) -bool CryRWLock::TryLock() -{ - return TryWLock(); -} -#endif - -////////////////////////////////////////////////////////////////////////// -void CryRWLock::Unlock() -{ - WUnlock(); -} - ////////////////////////////////////////////////////////////////////////// CrySimpleThreadSelf::CrySimpleThreadSelf() : m_thread(NULL) @@ -415,181 +343,3 @@ void CrySimpleThreadSelf::StartThread(unsigned (__stdcall * func)(void*), void* PREFAST_ASSUME(m_thread); ResumeThread((HANDLE)m_thread); } - - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -void CryInterlockedPushEntrySList(SLockFreeSingleLinkedListHeader& list, SLockFreeSingleLinkedListEntry& element) -{ - STATIC_CHECK(sizeof(SLockFreeSingleLinkedListHeader) == sizeof(SLIST_HEADER), CRY_INTERLOCKED_SLIST_HEADER_HAS_WRONG_SIZE); - STATIC_CHECK(sizeof(SLockFreeSingleLinkedListEntry) >= sizeof(SLIST_ENTRY), CRY_INTERLOCKED_SLIST_ENTRY_HAS_WRONG_SIZE); - - assert(IsAligned(&list, MEMORY_ALLOCATION_ALIGNMENT) && "LockFree SingleLink List Header has wrong Alignment"); - assert(IsAligned(&element, MEMORY_ALLOCATION_ALIGNMENT) && "LockFree SingleLink List Entry has wrong Alignment"); - InterlockedPushEntrySList(alias_cast(&list), alias_cast(&element)); -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list) -{ - STATIC_CHECK(sizeof(SLockFreeSingleLinkedListHeader) == sizeof(SLIST_HEADER), CRY_INTERLOCKED_SLIST_HEADER_HAS_WRONG_SIZE); - - assert(IsAligned(&list, MEMORY_ALLOCATION_ALIGNMENT) && "LockFree SingleLink List Header has wrong Alignment"); - return reinterpret_cast(InterlockedPopEntrySList(alias_cast(&list))); -} - -////////////////////////////////////////////////////////////////////////// -void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list) -{ - assert(IsAligned(&list, MEMORY_ALLOCATION_ALIGNMENT) && "LockFree SingleLink List Header has wrong Alignment"); - - STATIC_CHECK(sizeof(SLockFreeSingleLinkedListHeader) == sizeof(SLIST_HEADER), CRY_INTERLOCKED_SLIST_HEADER_HAS_WRONG_SIZE); - InitializeSListHead(alias_cast(&list)); -} - -////////////////////////////////////////////////////////////////////////// -void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list) -{ - assert(IsAligned(&list, MEMORY_ALLOCATION_ALIGNMENT) && "LockFree SingleLink List Header has wrong Alignment"); - - STATIC_CHECK(sizeof(SLockFreeSingleLinkedListHeader) == sizeof(SLIST_HEADER), CRY_INTERLOCKED_SLIST_HEADER_HAS_WRONG_SIZE); - return InterlockedFlushSList(alias_cast(&list)); -} - -/////////////////////////////////////////////////////////////////////////////// -// base class for lock less Producer/Consumer queue, due platforms specific they -// are implemeted in CryThead_platform.h -namespace CryMT { - namespace detail { - /////////////////////////////////////////////////////////////////////////////// - void SingleProducerSingleConsumerQueueBase::Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize) - { - // spin if queue is full - int iter = 0; - while (rProducerIndex - rComsumerIndex == nBufferSize) - { - CryLowLatencySleep(iter++ > 10 ? 1 : 0); - } - - MemoryBarrier(); - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rProducerIndex % nBufferSize; - - memcpy(pBuffer + (nIndex * nObjectSize), pObj, nObjectSize); - MemoryBarrier(); - rProducerIndex += 1; - MemoryBarrier(); - } - - /////////////////////////////////////////////////////////////////////////////// - void SingleProducerSingleConsumerQueueBase::Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize) - { - MemoryBarrier(); - // busy-loop if queue is empty - int iter = 0; - while (rProducerIndex - rComsumerIndex == 0) - { - CryLowLatencySleep(iter++ > 10 ? 1 : 0); - } - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rComsumerIndex % nBufferSize; - - memcpy(pObj, pBuffer + (nIndex * nObjectSize), nObjectSize); - MemoryBarrier(); - rComsumerIndex += 1; - MemoryBarrier(); - } - - /////////////////////////////////////////////////////////////////////////////// - void N_ProducerSingleConsumerQueueBase::Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, [[maybe_unused]] volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates) - { - MemoryBarrier(); - uint32 nProducerIndex; - uint32 nComsumerIndex; - - int iter = 0; - do - { - nProducerIndex = rProducerIndex; - nComsumerIndex = rComsumerIndex; - - if (nProducerIndex - nComsumerIndex == nBufferSize) - { - CryLowLatencySleep(iter++ > 10 ? 1 : 0); - if (iter > 20) // 10 spins + 10 ms wait - { - uint32 nSizeToAlloc = sizeof(SFallbackList) + nObjectSize - 1; - SFallbackList* pFallbackEntry = (SFallbackList*)CryModuleMemalign(nSizeToAlloc, 128); - memcpy(pFallbackEntry->object, pObj, nObjectSize); - MemoryBarrier(); - CryInterlockedPushEntrySList(fallbackList, pFallbackEntry->nextEntry); - return; - } - continue; - } - - if (CryInterlockedCompareExchange(alias_cast(&rProducerIndex), nProducerIndex + 1, nProducerIndex) == nProducerIndex) - { - break; - } - } while (true); - - MemoryBarrier(); - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = nProducerIndex % nBufferSize; - - memcpy(pBuffer + (nIndex * nObjectSize), pObj, nObjectSize); - MemoryBarrier(); - arrStates[nIndex] = 1; - MemoryBarrier(); - } - - /////////////////////////////////////////////////////////////////////////////// - bool N_ProducerSingleConsumerQueueBase::Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates) - { - MemoryBarrier(); - - // busy-loop if queue is empty - int iter = 0; - if (rRunning && rProducerIndex - rComsumerIndex == 0) - { - while (rRunning && rProducerIndex - rComsumerIndex == 0) - { - CryLowLatencySleep(iter++ > 10 ? 1 : 0); - } - } - - if (rRunning == 0 && rProducerIndex - rComsumerIndex == 0) - { - SFallbackList* pFallback = (SFallbackList*)CryInterlockedPopEntrySList(fallbackList); - IF (pFallback, 0) - { - memcpy(pObj, pFallback->object, nObjectSize); - CryModuleMemalignFree(pFallback); - return true; - } - // if the queue was empty, make sure we really are empty - return false; - } - - iter = 0; - while (arrStates[rComsumerIndex % nBufferSize] == 0) - { - CryLowLatencySleep(iter++ > 10 ? 1 : 0); - } - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rComsumerIndex % nBufferSize; - - memcpy(pObj, pBuffer + (nIndex * nObjectSize), nObjectSize); - MemoryBarrier(); - arrStates[nIndex] = 0; - MemoryBarrier(); - rComsumerIndex += 1; - MemoryBarrier(); - - return true; - } - } // namespace detail -} // namespace CryMT diff --git a/Code/Legacy/CryCommon/CryThread_pthreads.h b/Code/Legacy/CryCommon/CryThread_pthreads.h index 4ebc4e9637..72b29344ec 100644 --- a/Code/Legacy/CryCommon/CryThread_pthreads.h +++ b/Code/Legacy/CryCommon/CryThread_pthreads.h @@ -524,57 +524,6 @@ inline void CryFastSemaphore::Release() } } -////////////////////////////////////////////////////////////////////////// -#if !defined _CRYTHREAD_HAVE_RWLOCK -class CryRWLock -{ - pthread_rwlock_t m_Lock; - - CryRWLock(const CryRWLock&); - CryRWLock& operator= (const CryRWLock&); - -public: - CryRWLock() { pthread_rwlock_init(&m_Lock, NULL); } - ~CryRWLock() { pthread_rwlock_destroy(&m_Lock); } - void RLock() { pthread_rwlock_rdlock(&m_Lock); } - bool TryRLock() - { -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_TRY_RLOCK - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - return pthread_rwlock_tryrdlock(&m_Lock) != EBUSY; -#endif - } - void RUnlock() { Unlock(); } - void WLock() { pthread_rwlock_wrlock(&m_Lock); } - bool TryWLock() - { -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_TRY_RLOCK - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - return pthread_rwlock_trywrlock(&m_Lock) != EBUSY; -#endif - } - void WUnlock() { Unlock(); } - void Lock() { WLock(); } - bool TryLock() { return TryWLock(); } - void Unlock() { pthread_rwlock_unlock(&m_Lock); } -}; - -// Indicate that this implementation header provides an implementation for -// CryRWLock. -#define _CRYTHREAD_HAVE_RWLOCK 1 -#endif // !defined _CRYTHREAD_HAVE_RWLOCK - - //////////////////////////////////////////////////////////////////////////////// // Provide TLS implementation using pthreads for those platforms without __thread //////////////////////////////////////////////////////////////////////////////// @@ -1145,185 +1094,3 @@ public: }; #include "MemoryAccess.h" - - /////////////////////////////////////////////////////////////////////////////// - // base class for lock less Producer/Consumer queue, due platforms specific they - // are implemeted in CryThead_platform.h - namespace CryMT { - namespace detail { - /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// - class SingleProducerSingleConsumerQueueBase - { - public: - SingleProducerSingleConsumerQueueBase() - {} - - void Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize); - void Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize); - }; - - /////////////////////////////////////////////////////////////////////////////// - inline void SingleProducerSingleConsumerQueueBase::Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize) - { - MemoryBarrier(); - // spin if queue is full - int iter = 0; - while (rProducerIndex - rComsumerIndex == nBufferSize) - { - Sleep(iter++ > 10 ? 1 : 0); - } - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rProducerIndex % nBufferSize; - memcpy(pBuffer + (nIndex * nObjectSize), pObj, nObjectSize); - - MemoryBarrier(); - rProducerIndex += 1; - MemoryBarrier(); - } - - /////////////////////////////////////////////////////////////////////////////// - inline void SingleProducerSingleConsumerQueueBase::Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize) - { - MemoryBarrier(); - // busy-loop if queue is empty - int iter = 0; - while (rProducerIndex - rComsumerIndex == 0) - { - Sleep(iter++ > 10 ? 1 : 0); - } - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rComsumerIndex % nBufferSize; - - memcpy(pObj, pBuffer + (nIndex * nObjectSize), nObjectSize); - - MemoryBarrier(); - rComsumerIndex += 1; - MemoryBarrier(); - } - - - /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// - class N_ProducerSingleConsumerQueueBase - { - public: - N_ProducerSingleConsumerQueueBase() - { - CryInitializeSListHead(fallbackList); - } - - void Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates); - bool Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates); - - SLockFreeSingleLinkedListHeader fallbackList; - struct SFallbackList - { - SLockFreeSingleLinkedListEntry nextEntry; - char alignment_padding[128 - sizeof(SLockFreeSingleLinkedListEntry)]; - char object[1]; // struct will be overallocated with enough memory for the object - }; - }; - - /////////////////////////////////////////////////////////////////////////////// - inline void N_ProducerSingleConsumerQueueBase::Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates) - { - MemoryBarrier(); - uint32 nProducerIndex; - uint32 nComsumerIndex; - - int iter = 0; - do - { - nProducerIndex = rProducerIndex; - nComsumerIndex = rComsumerIndex; - - if (nProducerIndex - nComsumerIndex == nBufferSize) - { - Sleep(iter++ > 10 ? 1 : 0); - if (iter > 20) // 10 spins + 10 ms wait - { - uint32 nSizeToAlloc = sizeof(SFallbackList) + nObjectSize - 1; - SFallbackList* pFallbackEntry = (SFallbackList*)CryModuleMemalign(nSizeToAlloc, 128); - memcpy(pFallbackEntry->object, pObj, nObjectSize); - CryInterlockedPushEntrySList(fallbackList, pFallbackEntry->nextEntry); - return; - } - continue; - } - - if (CryInterlockedCompareExchange(alias_cast(&rProducerIndex), nProducerIndex + 1, nProducerIndex) == nProducerIndex) - { - break; - } - } while (true); - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = nProducerIndex % nBufferSize; - - memcpy(pBuffer + (nIndex * nObjectSize), pObj, nObjectSize); - - MemoryBarrier(); - arrStates[nIndex] = 1; - MemoryBarrier(); - } - - /////////////////////////////////////////////////////////////////////////////// - inline bool N_ProducerSingleConsumerQueueBase::Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates) - { - MemoryBarrier(); - // busy-loop if queue is empty - int iter = 0; - do - { - SFallbackList* pFallback = (SFallbackList*)CryInterlockedPopEntrySList(fallbackList); - IF (pFallback, 0) - { - memcpy(pObj, pFallback->object, nObjectSize); - CryModuleMemalignFree(pFallback); - return true; - } - - if (iter > 10) - { - Sleep(iter > 100 ? 1 : 0); - } - iter++; - } while (rRunning && rProducerIndex - rComsumerIndex == 0); - - if (rRunning == 0 && rProducerIndex - rComsumerIndex == 0) - { - // if the queue was empty, make sure we really are empty - SFallbackList* pFallback = (SFallbackList*)CryInterlockedPopEntrySList(fallbackList); - IF (pFallback, 0) - { - memcpy(pObj, pFallback->object, nObjectSize); - CryModuleMemalignFree(pFallback); - return true; - } - return false; - } - - iter = 0; - while (arrStates[rComsumerIndex % nBufferSize] == 0) - { - Sleep(iter++ > 10 ? 1 : 0); - } - - char* pBuffer = alias_cast(arrBuffer); - uint32 nIndex = rComsumerIndex % nBufferSize; - - memcpy(pObj, pBuffer + (nIndex * nObjectSize), nObjectSize); - - MemoryBarrier(); - arrStates[nIndex] = 0; - MemoryBarrier(); - rComsumerIndex += 1; - MemoryBarrier(); - - return true; - } - } // namespace detail - } // namespace CryMT diff --git a/Code/Legacy/CryCommon/CryThread_windows.h b/Code/Legacy/CryCommon/CryThread_windows.h index b80666ce73..cc09cc530b 100644 --- a/Code/Legacy/CryCommon/CryThread_windows.h +++ b/Code/Legacy/CryCommon/CryThread_windows.h @@ -180,41 +180,6 @@ private: volatile int32 m_nCounter; }; -////////////////////////////////////////////////////////////////////////// -#if !defined(_CRYTHREAD_HAVE_RWLOCK) -class CryRWLock -{ - void* /*SRWLOCK*/ m_Lock; - - CryRWLock(const CryRWLock&); - CryRWLock& operator= (const CryRWLock&); - -public: - CryRWLock(); - ~CryRWLock(); - - void RLock(); - void RUnlock(); - - void WLock(); - void WUnlock(); - - void Lock(); - void Unlock(); - -#if defined(_CRYTHREAD_WANT_TRY_RWLOCK) - // Enabling TryXXX requires Windows 7 or newer - bool TryRLock(); - bool TryWLock(); - bool TryLock(); -#endif -}; - -// Indicate that this implementation header provides an implementation for -// CryRWLock. -#define _CRYTHREAD_HAVE_RWLOCK 1 -#endif - ////////////////////////////////////////////////////////////////////////// class CrySimpleThreadSelf { @@ -420,46 +385,3 @@ public: bool IsStarted() const { return m_bIsStarted; } bool IsRunning() const { return m_bIsRunning; } }; - -/////////////////////////////////////////////////////////////////////////////// -// base class for lock less Producer/Consumer queue, due platforms specific they -// are implemented in CryThead_platform.h -namespace CryMT { - namespace detail { - /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// - class SingleProducerSingleConsumerQueueBase - { - public: - SingleProducerSingleConsumerQueueBase() - {} - - void Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize); - void Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, uint32 nBufferSize, void* arrBuffer, uint32 nObjectSize); - }; - - - /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// - class N_ProducerSingleConsumerQueueBase - { - public: - N_ProducerSingleConsumerQueueBase() - { - CryInitializeSListHead(fallbackList); - } - - void Push(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates); - bool Pop(void* pObj, volatile uint32& rProducerIndex, volatile uint32& rComsumerIndex, volatile uint32& rRunning, void* arrBuffer, uint32 nBufferSize, uint32 nObjectSize, volatile uint32* arrStates); - - private: - SLockFreeSingleLinkedListHeader fallbackList; - struct SFallbackList - { - SLockFreeSingleLinkedListEntry nextEntry; - char alignment_padding[128 - sizeof(SLockFreeSingleLinkedListEntry)]; - char object[1]; // struct will be overallocated with enough memory for the object - }; - }; - } // namespace detail -} // namespace CryMT diff --git a/Code/Legacy/CryCommon/Linux_Win32Wrapper.h b/Code/Legacy/CryCommon/Linux_Win32Wrapper.h index 2dea83925d..23cd7faf7f 100644 --- a/Code/Legacy/CryCommon/Linux_Win32Wrapper.h +++ b/Code/Legacy/CryCommon/Linux_Win32Wrapper.h @@ -145,9 +145,6 @@ inline void MemoryBarrier() { typedef int64 __m128; #endif -#if defined(LINUX64) || defined(APPLE) -unsigned char _InterlockedCompareExchange128(int64 volatile* dst, int64 exchangehigh, int64 exchangelow, int64* comperand); -#endif ////////////////////////////////////////////////////////////////////////// // io.h stuff #if !defined(ANDROID) diff --git a/Code/Legacy/CryCommon/MultiThread.h b/Code/Legacy/CryCommon/MultiThread.h index 2454ade6ab..2b224c4743 100644 --- a/Code/Legacy/CryCommon/MultiThread.h +++ b/Code/Legacy/CryCommon/MultiThread.h @@ -29,78 +29,13 @@ #define MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDCOMPAREEXCHANGE64 8 #endif -#define THREAD_NAME_LENGTH_MAX 64 - #define WRITE_LOCK_VAL (1 << 16) // Traits #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_TRAITS #include AZ_RESTRICTED_FILE(MultiThread_h) -#else -#define MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_ATTRIBUTE_ALIGN_16 0 -#if defined(WIN64) -#define MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_MSALIGN_16 1 #endif -#if defined(APPLE) || defined(LINUX) -#define MULTITHREAD_H_TRAIT_USE_SALTED_LINKEDLISTHEADER 1 -#endif -#endif - -//as PowerPC operates via cache line reservation, lock variables should reside ion their own cache line -template -struct SAtomicVar -{ - T val; - - inline operator T() const{return val; } - inline operator T() volatile const{return val; } - inline SAtomicVar& operator =(const T& rV){val = rV; return *this; } - inline void Assign(const T& rV){val = rV; } - inline void Assign(const T& rV) volatile{val = rV; } - inline T* Addr() {return &val; } - inline volatile T* Addr() volatile {return &val; } - - inline bool operator<(const T& v) const{return val < v; } - inline bool operator<(const SAtomicVar& v) const{return val < v.val; } - inline bool operator>(const T& v) const{return val > v; } - inline bool operator>(const SAtomicVar& v) const{return val > v.val; } - inline bool operator<=(const T& v) const{return val <= v; } - inline bool operator<=(const SAtomicVar& v) const{return val <= v.val; } - inline bool operator>=(const T& v) const{return val >= v; } - inline bool operator>=(const SAtomicVar& v) const{return val >= v.val; } - inline bool operator==(const T& v) const{return val == v; } - inline bool operator==(const SAtomicVar& v) const{return val == v.val; } - inline bool operator!=(const T& v) const{return val != v; } - inline bool operator!=(const SAtomicVar& v) const{return val != v.val; } - inline T operator*(const T& v) const{return val * v; } - inline T operator/(const T& v) const{return val / v; } - inline T operator+(const T& v) const{return val + v; } - inline T operator-(const T& v) const{return val - v; } - - inline bool operator<(const T& v) volatile const{return val < v; } - inline bool operator<(const SAtomicVar& v) volatile const{return val < v.val; } - inline bool operator>(const T& v) volatile const{return val > v; } - inline bool operator>(const SAtomicVar& v) volatile const{return val > v.val; } - inline bool operator<=(const T& v) volatile const{return val <= v; } - inline bool operator<=(const SAtomicVar& v) volatile const{return val <= v.val; } - inline bool operator>=(const T& v) volatile const{return val >= v; } - inline bool operator>=(const SAtomicVar& v) volatile const{return val >= v.val; } - inline bool operator==(const T& v) volatile const{return val == v; } - inline bool operator==(const SAtomicVar& v) volatile const{return val == v.val; } - inline bool operator!=(const T& v) volatile const{return val != v; } - inline bool operator!=(const SAtomicVar& v) volatile const{return val != v.val; } - inline T operator*(const T& v) volatile const{return val * v; } - inline T operator/(const T& v) volatile const{return val / v; } - inline T operator+(const T& v) volatile const{return val + v; } - inline T operator-(const T& v) volatile const{return val - v; } -}; - -typedef SAtomicVar TIntAtomic; -typedef SAtomicVar TUIntAtomic; -typedef SAtomicVar TFloatAtomic; - -#define __add_db16cycl__ NIntrinsics::YieldFor16Cycles(); void CrySpinLock(volatile int* pLock, int checkVal, int setVal); void CryReleaseSpinLock (volatile int*, int); @@ -208,37 +143,6 @@ ILINE void CryReleaseSpinLock(volatile int* pLock, int setVal) } ////////////////////////////////////////////////////////////////////////// -#if defined(APPLE) || defined(LINUX64) -// Fixes undefined reference to CryInterlockedAdd(unsigned long volatile*, long) on -// Mac and linux. -ILINE void CryInterLockedAdd(volatile LONG* pVal, LONG iAdd) -{ - (void) CryInterlockedExchangeAdd(pVal, iAdd); -} - - -/* -ILINE void CryInterLockedAdd(volatile unsigned long *pVal, long iAdd) -{ - long r; - __asm__ __volatile__ ( - #if defined(LINUX64) || defined(MAC) // long is 64 bits on amd64. - "lock ; xaddq %0, (%1) \n\t" - #else - "lock ; xaddl %0, (%1) \n\t" - #endif - : "=r" (r) - : "r" (pVal), "0" (iAdd) - : "memory" - ); - (void) r; -}*/ -/*ILINE void CryInterlockedAdd(volatile size_t *pVal, ptrdiff_t iAdd) { - //(void)CryInterlockedExchangeAdd((volatile long*)pVal,(long)iAdd); - (void) __sync_fetch_and_add(pVal,iAdd); -}*/ - -#endif ILINE void CryInterlockedAdd(volatile int* pVal, int iAdd) { #ifdef _CPU_X86 @@ -311,123 +215,6 @@ ILINE void CryInterlockedAddSize(volatile size_t* pVal, ptrdiff_t iAdd) ////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -// CryInterlocked*SList Function, these are specialized C-A-S -// functions for single-linked lists which prevent the A-B-A problem there -// there are implemented in the platform specific CryThread_*.h files -// TODO clean up the interlocked function the same was the CryThread_* header are - -//TODO somehow get their real size on WIN (without including windows.h...) -//NOTE: The sizes are verifyed at compile-time in the implementation functions, but this is still ugly -#if MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_MSALIGN_16 -_MS_ALIGN(16) -#elif defined(WIN32) -_MS_ALIGN(8) -#endif -struct SLockFreeSingleLinkedListEntry -{ - SLockFreeSingleLinkedListEntry* volatile pNext; -} -#if MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_ATTRIBUTE_ALIGN_16 -__attribute__ ((aligned(16))) -#elif defined(LINUX32) -_ALIGN(8) -#elif defined(APPLE) || defined(LINUX64) -_ALIGN(16) -#endif -; - -#if MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_MSALIGN_16 -_MS_ALIGN(16) -#elif defined(WIN32) -_MS_ALIGN(8) -#endif -struct SLockFreeSingleLinkedListHeader -{ - SLockFreeSingleLinkedListEntry* volatile pNext; -#if defined(INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED) - // arm64 processors do not provide a cmpxchg16b (or equivalent) instruction, - // so _InterlockedCompareExchange128 is not implemented on arm64 platforms, - // and we have to use a mutex to ensure thread safety. - AZStd::mutex mutex; -#elif MULTITHREAD_H_TRAIT_USE_SALTED_LINKEDLISTHEADER - // If pointers 32bit, salt should be as well. Otherwise we get 4 bytes of padding between pNext and salt and CAS operations fail -#if defined(PLATFORM_64BIT) - volatile uint64 salt; -#else - volatile uint32 salt; -#endif -#endif -} -#if MULTITHREAD_H_TRAIT_SLOCKFREESINGLELINKEDLISTENTRY_ATTRIBUTE_ALIGN_16 -__attribute__ ((aligned(16))) -#elif defined(LINUX32) -_ALIGN(8) -#elif defined(APPLE) || defined(LINUX64) -_ALIGN(16) -#endif -; - - -// push a element atomically onto a single linked list -void CryInterlockedPushEntrySList(SLockFreeSingleLinkedListHeader& list, SLockFreeSingleLinkedListEntry& element); - -// push a element atomically from a single linked list -void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list); - -// initialzied the lock-free single linked list -void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list); - -// flush the whole list -void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list); - -ILINE void CryReadLock(volatile int* rw, bool yield) -{ - CryInterlockedAdd(rw, 1); -#ifdef NEED_ENDIAN_SWAP - volatile char* pw = (volatile char*)rw + 1; -#else - volatile char* pw = (volatile char*)rw + 2; -#endif - - uint64 loops = 0; - for (; *pw; ) - { - if (yield) - { -# if !defined(ANDROID) && !defined(IOS) && !defined(MULTITHREAD_H_TRAIT_NO_MM_PAUSE) - _mm_pause(); -# endif - - if (!(++loops & 0x7F)) - { - // give other threads with other prio right to run -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_CRYINTERLOCKEDFLUSHSLIST_PT1 - #include AZ_RESTRICTED_FILE(MultiThread_h) -#elif defined (LINUX) - usleep(1); -#endif - } - else if (!(loops & 0x3F)) - { - // give threads with same prio chance to run -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_CRYINTERLOCKEDFLUSHSLIST_PT2 - #include AZ_RESTRICTED_FILE(MultiThread_h) -#elif defined (LINUX) - sched_yield(); -#endif - } - } - } -} - -ILINE void CryReleaseReadLock(volatile int* rw) -{ - CryInterlockedAdd(rw, -1); -} - ILINE void CryWriteLock(volatile int* rw) { CrySpinLock(rw, 0, WRITE_LOCK_VAL); @@ -438,78 +225,6 @@ ILINE void CryReleaseWriteLock(volatile int* rw) CryInterlockedAdd(rw, -WRITE_LOCK_VAL); } -////////////////////////////////////////////////////////////////////////// -struct ReadLock -{ - ILINE ReadLock(volatile int& rw) - { - CryInterlockedAdd(prw = &rw, 1); -#ifdef NEED_ENDIAN_SWAP - volatile char* pw = (volatile char*)&rw + 1; - for (; * pw; ) - { - ; - } -#else - volatile char* pw = (volatile char*)&rw + 2; - for (; * pw; ) - { - ; - } -#endif - } - ILINE ReadLock(volatile int& rw, bool yield) - { - CryReadLock(prw = &rw, yield); - } - ~ReadLock() - { - CryReleaseReadLock(prw); - } -private: - volatile int* prw; -}; - -struct ReadLockCond -{ - ILINE ReadLockCond(volatile int& rw, int bActive) - { - if (bActive) - { - CryInterlockedAdd(&rw, 1); - bActivated = 1; -#ifdef NEED_ENDIAN_SWAP - volatile char* pw = (volatile char*)&rw + 1; - for (; * pw; ) - { - ; - } -#else - volatile char* pw = (volatile char*)&rw + 2; - for (; * pw; ) - { - ; - } -#endif - } - else - { - bActivated = 0; - } - prw = &rw; - } - void SetActive(int bActive = 1) { bActivated = bActive; } - void Release() { CryInterlockedAdd(prw, -bActivated); } - ~ReadLockCond() - { - CryInterlockedAdd(prw, -bActivated); - } - -private: - volatile int* prw; - int bActivated; -}; - ////////////////////////////////////////////////////////////////////////// struct WriteLock { @@ -519,15 +234,6 @@ private: volatile int* prw; }; -////////////////////////////////////////////////////////////////////////// -struct WriteAfterReadLock -{ - ILINE WriteAfterReadLock(volatile int& rw) { CrySpinLock(&rw, 1, WRITE_LOCK_VAL + 1); prw = &rw; } - ~WriteAfterReadLock() { CryInterlockedAdd(prw, -WRITE_LOCK_VAL); } -private: - volatile int* prw; -}; - ////////////////////////////////////////////////////////////////////////// struct WriteLockCond { @@ -562,12 +268,6 @@ ILINE int64 CryInterlockedCompareExchange64(volatile int64* addr, int64 exchange // This is OK, because long is signed int64 on Linux x86_64 //return CryInterlockedCompareExchange((volatile long*)addr, (long)exchange, (long)comperand); } - -ILINE int64 CryInterlockedExchange64(volatile int64* addr, int64 exchange) -{ - __sync_synchronize(); - return __sync_lock_test_and_set(addr, exchange); -} #else ILINE int64 CryInterlockedCompareExchange64(volatile int64* addr, int64 exchange, int64 compare) { @@ -583,21 +283,3 @@ ILINE int64 CryInterlockedCompareExchange64(volatile int64* addr, int64 exchange #endif } #endif - -////////////////////////////////////////////////////////////////////////// -#if defined(EXCLUDE_PHYSICS_THREAD) -ILINE void SpinLock(volatile int* pLock, int checkVal, int setVal) { *(int*)pLock = setVal; } -ILINE void AtomicAdd(volatile int* pVal, int iAdd) { *(int*)pVal += iAdd; } -ILINE void AtomicAdd(volatile unsigned int* pVal, int iAdd) { *(unsigned int*)pVal += iAdd; } - -ILINE void JobSpinLock(volatile int* pLock, int checkVal, int setVal) { CrySpinLock(pLock, checkVal, setVal); } -#else -ILINE void SpinLock(volatile int* pLock, int checkVal, int setVal) { CrySpinLock(pLock, checkVal, setVal); } -ILINE void AtomicAdd(volatile int* pVal, int iAdd) { CryInterlockedAdd(pVal, iAdd); } -ILINE void AtomicAdd(volatile unsigned int* pVal, int iAdd) { CryInterlockedAdd((volatile int*)pVal, iAdd); } - -ILINE void JobSpinLock(volatile int* pLock, int checkVal, int setVal) { SpinLock(pLock, checkVal, setVal); } -#endif - -ILINE void JobAtomicAdd(volatile int* pVal, int iAdd) { CryInterlockedAdd(pVal, iAdd); } -ILINE void JobAtomicAdd(volatile unsigned int* pVal, int iAdd) { CryInterlockedAdd((volatile int*)pVal, iAdd); } diff --git a/Code/Legacy/CryCommon/MultiThread_Containers.h b/Code/Legacy/CryCommon/MultiThread_Containers.h index 7c5af2a5d0..23f7cd1e0c 100644 --- a/Code/Legacy/CryCommon/MultiThread_Containers.h +++ b/Code/Legacy/CryCommon/MultiThread_Containers.h @@ -94,325 +94,10 @@ namespace CryMT container_type v; mutable CryCriticalSection m_cs; }; - - ////////////////////////////////////////////////////////////////////////// - // Multi-Thread safe vector container, can be used instead of std::vector. - ////////////////////////////////////////////////////////////////////////// - template - class vector - { - public: - typedef T value_type; - typedef CryAutoCriticalSection AutoLock; - - CryCriticalSection& get_lock() const { return m_cs; } - - void free_memory() { AutoLock lock(m_cs); stl::free_container(v); } - - ////////////////////////////////////////////////////////////////////////// - // std::vector interface - ////////////////////////////////////////////////////////////////////////// - bool empty() const { AutoLock lock(m_cs); return v.empty(); } - int size() const { AutoLock lock(m_cs); return v.size(); } - void resize(int sz) { AutoLock lock(m_cs); v.resize(sz); } - void reserve(int sz) { AutoLock lock(m_cs); v.reserve(sz); } - size_t capacity() const { AutoLock lock(m_cs); return v.size(); } - void clear() { AutoLock lock(m_cs); v.clear(); } - T& operator[](size_t pos) { AutoLock lock(m_cs); return v[pos]; } - const T& operator[](size_t pos) const { AutoLock lock(m_cs); return v[pos]; } - const T& front() const { AutoLock lock(m_cs); return v.front(); } - const T& back() const { AutoLock lock(m_cs); return v.back(); } - T& back() { AutoLock lock(m_cs); return v.back(); } - - void push_back(const T& x) { AutoLock lock(m_cs); return v.push_back(x); } - void pop_back() { AutoLock lock(m_cs); return v.pop_back(); } - ////////////////////////////////////////////////////////////////////////// - - template - void sort(const Func& compare_less) { AutoLock lock(m_cs); std::sort(v.begin(), v.end(), compare_less); } - - template - void append(const Iter& startRange, const Iter& endRange) { AutoLock lock(m_cs); v.insert(v.end(), startRange, endRange); } - - void swap(std::vector& vec) { AutoLock lock(m_cs); v.swap(vec); } - - ////////////////////////////////////////////////////////////////////////// - bool try_pop_front(T& returnValue) - { - AutoLock lock(m_cs); - if (!v.empty()) - { - returnValue = v.front(); - v.erase(v.begin()); - return true; - } - return false; - }; - bool try_pop_back(T& returnValue) - { - AutoLock lock(m_cs); - if (!v.empty()) - { - returnValue = v.back(); - v.pop_back(); - return true; - } - return false; - }; - - ////////////////////////////////////////////////////////////////////////// - template - bool find_and_copy(FindFunction findFunc, const KeyType& key, T& foundValue) const - { - AutoLock lock(m_cs); - if (!v.empty()) - { - typename std::vector::const_iterator it; - for (it = v.begin(); it != v.end(); ++it) - { - if (findFunc(key, *it)) - { - foundValue = *it; - return true; - } - } - } - return false; - } - - ////////////////////////////////////////////////////////////////////////// - bool try_remove(const T& value) - { - AutoLock lock(m_cs); - if (!v.empty()) - { - typename std::vector::iterator it = std::find(v.begin(), v.end(), value); - if (it != v.end()) - { - v.erase(it); - return true; - } - } - return false; - }; - - ////////////////////////////////////////////////////////////////////////// - template - bool try_remove_and_erase_if(Predicate predicateFunction) - { - AutoLock lock(m_cs); - if (!v.empty()) - { - typename std::vector::iterator it = std::remove_if(v.begin(), v.end(), predicateFunction); - if (it != v.end()) - { - v.erase(it, v.end()); - return true; - } - } - return false; - }; - - - ////////////////////////////////////////////////////////////////////////// - bool try_remove_at(size_t idx) - { - AutoLock lock(m_cs); - if (idx < v.size()) - { - v.erase(v.begin() + idx); - return true; - } - return false; - } - - - ////////////////////////////////////////////////////////////////////////// - //Fast remove - just move last elem over deleted element - order is not preserved - bool try_remove_unordered(const T& value) - { - AutoLock lock(m_cs); - if (!v.empty()) - { - typename std::vector::iterator it = std::find(v.begin(), v.end(), value); - if (it != v.end()) - { - if (v.size() > 1) - { - typename std::vector::iterator it_back = v.end() - 1; - - if (it != it_back) - { - *it = *it_back; - } - - v.erase(it_back); - } - else - { - v.erase(it); - } - return true; - } - } - return false; - }; - - vector() {} - - vector(const vector& rOther) - { - AutoLock lock1(m_cs); - AutoLock lock2(rOther.m_cs); - - v = rOther.v; - } - - vector& operator=(const vector& rOther) - { - if (this == &rOther) - { - return *this; - } - - AutoLock lock1(m_cs); - AutoLock lock2(rOther.m_cs); - - v = rOther.v; - - return *this; - } - private: - std::vector v; - mutable CryCriticalSection m_cs; - }; - - - ////////////////////////////////////////////////////////////////////////// - // Multi-Thread safe set container, can be used instead of std::set. - // It has limited functionality, but most of it is there. - ////////////////////////////////////////////////////////////////////////// - template - class set - { - public: - typedef T value_type; - typedef T Key; - typedef typename std::set::size_type size_type; - typedef CryAutoCriticalSection AutoLock; - - ////////////////////////////////////////////////////////////////////////// - // Methods - ////////////////////////////////////////////////////////////////////////// - void clear() { AutoLock lock(m_cs); s.clear(); } - size_type count(const Key& _Key) const { AutoLock lock(m_cs); return s.count(_Key); } - bool empty() const { AutoLock lock(m_cs); return s.empty(); } - size_type erase(const Key& _Key) { AutoLock lock(m_cs); return s.erase(_Key); } - - bool find(const Key& _Key) { AutoLock lock(m_cs); return (s.find(_Key) != s.end()); } - - bool pop_front(value_type& rFrontElement) - { - AutoLock lock(m_cs); - if (s.empty()) - { - return false; - } - rFrontElement = *s.begin(); - s.erase(s.begin()); - return true; - } - bool pop_front() - { - AutoLock lock(m_cs); - if (s.empty()) - { - return false; - } - s.erase(s.begin()); - return true; - } - - bool front(value_type& rFrontElement) - { - AutoLock lock(m_cs); - if (s.empty()) - { - return false; - } - rFrontElement = *s.begin(); - return true; - } - - bool insert(const value_type& _Val) { AutoLock lock(m_cs); return s.insert(_Val).second; } - size_type max_size() const { AutoLock lock(m_cs); return s.max_size(); } - size_type size() const { AutoLock lock(m_cs); return s.size(); } - void swap(set& _Right) { AutoLock lock(m_cs); s.swap(_Right); } - - CryCriticalSection& get_lock() { return m_cs; } - - private: - std::set s; - mutable CryCriticalSection m_cs; - }; - - - /////////////////////////////////////////////////////////////////////////////// - // - // Multi-thread safe lock-less FIFO queue container for passing pointers between threads. - // The queue only stores pointers to T, it does not copy the contents of T. - // - ////////////////////////////////////////////////////////////////////////// - template > - class CLocklessPointerQueue - { - public: - explicit CLocklessPointerQueue(size_t reserve = 32) { m_lockFreeQueue.reserve(reserve); }; - ~CLocklessPointerQueue() {}; - - // Check's if queue is empty. - bool empty() const; - - // Pushes item to the queue, only pointer is stored, T contents are not copied. - void push(T* ptr); - // pop can return NULL, always check for it before use. - T* pop(); - - private: - queue::template rebind_alloc> m_lockFreeQueue; - }; - - ////////////////////////////////////////////////////////////////////////// - template - inline bool CLocklessPointerQueue::empty() const - { - return m_lockFreeQueue.empty(); - } - - ////////////////////////////////////////////////////////////////////////// - template - inline void CLocklessPointerQueue::push(T* ptr) - { - m_lockFreeQueue.push(ptr); - } - - ////////////////////////////////////////////////////////////////////////// - template - inline T* CLocklessPointerQueue::pop() - { - T* val = NULL; - m_lockFreeQueue.try_pop(val); - return val; - } }; // namespace CryMT namespace stl { - template - void free_container(CryMT::vector& v) - { - v.free_memory(); - } template void free_container(CryMT::queue& v) { diff --git a/Code/Legacy/CryCommon/WinBase.cpp b/Code/Legacy/CryCommon/WinBase.cpp index 3208da9d68..15146fbac1 100644 --- a/Code/Legacy/CryCommon/WinBase.cpp +++ b/Code/Legacy/CryCommon/WinBase.cpp @@ -1377,25 +1377,6 @@ DLL_EXPORT void* CryInterlockedExchangePointer(void* volatile* dst, void* ex //return (void*)CryInterlockedCompareExchange((long volatile*)dst, (long)exchange, (long)comperand); } -#if (defined(LINUX64) && !defined(ANDROID)) || defined(MAC) || defined(IOS_SIMULATOR) -DLL_EXPORT unsigned char _InterlockedCompareExchange128(int64 volatile* dst, int64 exchangehigh, int64 exchangelow, int64* comperand) -{ - bool bEquals; - __asm__ __volatile__ - ( - "lock cmpxchg16b %1\n\t" - "setz %0" - : "=q" (bEquals), "+m" (*dst), "+d" (comperand[1]), "+a" (comperand[0]) - : "c" (exchangehigh), "b" (exchangelow) - : "cc" - ); - return (char)bEquals; -} -#elif defined(INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED) - // arm64 processors do not provide a cmpxchg16b (or equivalent) instruction, - // so _InterlockedCompareExchange128 is not implemented on arm64 platforms. -#endif - threadID CryGetCurrentThreadId() { return GetCurrentThreadId(); diff --git a/Code/Legacy/CryCommon/iOSSpecific.h b/Code/Legacy/CryCommon/iOSSpecific.h index 36b50f0e3e..d2503a7441 100644 --- a/Code/Legacy/CryCommon/iOSSpecific.h +++ b/Code/Legacy/CryCommon/iOSSpecific.h @@ -34,10 +34,6 @@ #define PLATFORM_64BIT #endif -#if defined(_CPU_ARM) && defined(PLATFORM_64BIT) -# define INTERLOCKED_COMPARE_EXCHANGE_128_NOT_SUPPORTED -#endif // defined(_CPU_ARM) && defined(PLATFORM_64BIT) - #ifndef MOBILE #define MOBILE #endif