Merge branch 'development' into cmake/SPEC-2513_w4018
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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 LockClass>
|
||||
class CryOptionalAutoLock
|
||||
{
|
||||
private:
|
||||
LockClass* m_Lock;
|
||||
bool m_bLockAcquired;
|
||||
|
||||
CryOptionalAutoLock();
|
||||
CryOptionalAutoLock(const CryOptionalAutoLock<LockClass>&);
|
||||
CryOptionalAutoLock<LockClass>& operator = (const CryOptionalAutoLock<LockClass>&);
|
||||
|
||||
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 ValueClass>
|
||||
class CryAutoSet
|
||||
{
|
||||
private:
|
||||
ValueClass* m_pValue;
|
||||
|
||||
CryAutoSet();
|
||||
CryAutoSet(const CryAutoSet<ValueClass>&);
|
||||
CryAutoSet<ValueClass>& operator = (const CryAutoSet<ValueClass>&);
|
||||
|
||||
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<CryCriticalSection> CryAutoCriticalSection;
|
||||
|
||||
#define AUTO_LOCK_T(Type, lock) PREFAST_SUPPRESS_WARNING(6246); CryAutoLock<Type> __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 Runnable = CryRunnable>
|
||||
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 Runnable = CryRunnable>
|
||||
class CryThread;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Include architecture specific code.
|
||||
#if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS
|
||||
@@ -265,560 +182,5 @@ class CryThread;
|
||||
typedef CryLockT<CRYLOCK_RECURSIVE> 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 Runnable>
|
||||
class CryThread
|
||||
: public CrySimpleThread<Runnable>
|
||||
{
|
||||
CryMutex m_Lock;
|
||||
CryConditionVariable m_Cond;
|
||||
|
||||
CryThread(const CryThread<Runnable>&);
|
||||
void operator = (const CryThread<Runnable>&);
|
||||
|
||||
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 T, bool bDEBUG = false>
|
||||
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 T, bool bDEBUG = false>
|
||||
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<CryReadModifyLock> AZ_JOIN(__readlock, __LINE__)(p, __FUNC__)
|
||||
#define AUTO_READLOCK_PROT(p) PREFAST_SUPPRESS_WARNING(6246) AutoLockRead<CryReadModifyLock> AZ_JOIN(__readlock_prot, __LINE__)(p, __FUNC__)
|
||||
#define AUTO_MODIFYLOCK(p) PREFAST_SUPPRESS_WARNING(6246) AutoLockModify<CryReadModifyLock> AZ_JOIN(__modifylock, __LINE__)(p, __FUNC__)
|
||||
|
||||
#if defined(_DEBUG)
|
||||
#define DEBUG_READLOCK(p) AutoLockRead<CryReadModifyLock> AZ_JOIN(__readlock, __LINE__)(p, __FUNC__)
|
||||
#define DEBUG_MODIFYLOCK(p) AutoLockModify<CryReadModifyLock> 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<typename T>
|
||||
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<typename T>
|
||||
inline SingleProducerSingleConsumerQueue<T>::SingleProducerSingleConsumerQueue()
|
||||
: m_arrBuffer(NULL)
|
||||
, m_nBufferSize(0)
|
||||
, m_nProducerIndex(0)
|
||||
, m_nComsumerIndex(0)
|
||||
{}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline SingleProducerSingleConsumerQueue<T>::~SingleProducerSingleConsumerQueue()
|
||||
{
|
||||
CryModuleMemalignFree(m_arrBuffer);
|
||||
m_nBufferSize = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline void SingleProducerSingleConsumerQueue<T>::Init(size_t nSize)
|
||||
{
|
||||
assert(m_arrBuffer == NULL);
|
||||
assert(m_nBufferSize == 0);
|
||||
assert((nSize & (nSize - 1)) == 0);
|
||||
|
||||
m_arrBuffer = alias_cast<T*>(CryModuleMemalign(nSize * sizeof(T), 16));
|
||||
m_nBufferSize = nSize;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline void SingleProducerSingleConsumerQueue<T>::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<typename T>
|
||||
inline void SingleProducerSingleConsumerQueue<T>::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<typename T>
|
||||
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<typename T>
|
||||
inline N_ProducerSingleConsumerQueue<T>::N_ProducerSingleConsumerQueue()
|
||||
: m_arrBuffer(NULL)
|
||||
, m_arrStates(NULL)
|
||||
, m_nBufferSize(0)
|
||||
, m_nProducerIndex(0)
|
||||
, m_nComsumerIndex(0)
|
||||
, m_nRunning(0)
|
||||
, m_nProducerCount(0)
|
||||
{}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline N_ProducerSingleConsumerQueue<T>::~N_ProducerSingleConsumerQueue()
|
||||
{
|
||||
CryModuleMemalignFree(m_arrBuffer);
|
||||
CryModuleMemalignFree((void*)m_arrStates);
|
||||
m_nBufferSize = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline void N_ProducerSingleConsumerQueue<T>::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<T*>(CryModuleMemalign(nSize * sizeof(T), 16));
|
||||
m_arrStates = alias_cast<uint32*>(CryModuleMemalign(nSize * sizeof(uint32), 16));
|
||||
memset((void*)m_arrStates, 0, sizeof(uint32) * nSize);
|
||||
m_nBufferSize = nSize;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline void N_ProducerSingleConsumerQueue<T>::SetRunningState()
|
||||
{
|
||||
#if !defined(_RELEASE)
|
||||
if (m_nRunning == 1)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
m_nRunning = 1;
|
||||
m_nProducerCount = 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
inline void N_ProducerSingleConsumerQueue<T>::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<typename T>
|
||||
inline void N_ProducerSingleConsumerQueue<T>::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<typename T>
|
||||
inline void N_ProducerSingleConsumerQueue<T>::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<typename T>
|
||||
inline bool N_ProducerSingleConsumerQueue<T>::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"
|
||||
|
||||
@@ -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<AZStd::mutex> lock(list.mutex);
|
||||
|
||||
element.pNext = list.pNext;
|
||||
list.pNext = &element;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CryInterlockedPopEntrySList(SLockFreeSingleLinkedListHeader& list)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> lock(list.mutex);
|
||||
|
||||
SLockFreeSingleLinkedListEntry* returnValue = list.pNext;
|
||||
if (list.pNext)
|
||||
{
|
||||
list.pNext = list.pNext->pNext;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CryInitializeSListHead(SLockFreeSingleLinkedListHeader& list)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> lock(list.mutex);
|
||||
|
||||
list.pNext = NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void* CryInterlockedFlushSList(SLockFreeSingleLinkedListHeader& list)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> 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
|
||||
|
||||
@@ -303,78 +303,6 @@ void CryFastSemaphore::Release()
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CryRWLock::CryRWLock()
|
||||
{
|
||||
STATIC_ASSERT(sizeof(m_Lock) == sizeof(PSRWLOCK), "RWLock-pointer has invalid size");
|
||||
InitializeSRWLock(reinterpret_cast<PSRWLOCK>(&m_Lock));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CryRWLock::~CryRWLock()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CryRWLock::RLock()
|
||||
{
|
||||
AcquireSRWLockShared(reinterpret_cast<PSRWLOCK>(&m_Lock));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if defined(_CRYTHREAD_WANT_TRY_RWLOCK)
|
||||
bool CryRWLock::TryRLock()
|
||||
{
|
||||
return TryAcquireSRWLockShared(reinterpret_cast<PSRWLOCK>(&m_Lock)) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CryRWLock::RUnlock()
|
||||
{
|
||||
ReleaseSRWLockShared(reinterpret_cast<PSRWLOCK>(&m_Lock));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CryRWLock::WLock()
|
||||
{
|
||||
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&m_Lock));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if defined(_CRYTHREAD_WANT_TRY_RWLOCK)
|
||||
bool CryRWLock::TryWLock()
|
||||
{
|
||||
return TryAcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&m_Lock)) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CryRWLock::WUnlock()
|
||||
{
|
||||
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&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<PSLIST_HEADER>(&list), alias_cast<PSLIST_ENTRY>(&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<void*>(InterlockedPopEntrySList(alias_cast<PSLIST_HEADER>(&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<PSLIST_HEADER>(&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<PSLIST_HEADER>(&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<char*>(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<char*>(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<volatile LONG*>(&rProducerIndex), nProducerIndex + 1, nProducerIndex) == nProducerIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
MemoryBarrier();
|
||||
char* pBuffer = alias_cast<char*>(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<char*>(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
|
||||
|
||||
@@ -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<char*>(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<char*>(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<volatile LONG*>(&rProducerIndex), nProducerIndex + 1, nProducerIndex) == nProducerIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
char* pBuffer = alias_cast<char*>(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<char*>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -900,9 +900,6 @@ struct ISystem
|
||||
// Retrieves access to XML utilities interface.
|
||||
virtual IXmlUtils* GetXmlUtils() = 0;
|
||||
|
||||
virtual void SetViewCamera(CCamera& Camera) = 0;
|
||||
virtual CCamera& GetViewCamera() = 0;
|
||||
|
||||
// Description:
|
||||
// When ignore update sets to true, system will ignore and updates and render calls.
|
||||
virtual void IgnoreUpdates(bool bIgnore) = 0;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -100,10 +100,6 @@ public:
|
||||
XmlNodeRef(const char*, bool));
|
||||
MOCK_METHOD0(GetXmlUtils,
|
||||
IXmlUtils * ());
|
||||
MOCK_METHOD1(SetViewCamera,
|
||||
void(CCamera & Camera));
|
||||
MOCK_METHOD0(GetViewCamera,
|
||||
CCamera & ());
|
||||
MOCK_METHOD1(IgnoreUpdates,
|
||||
void(bool bIgnore));
|
||||
MOCK_METHOD1(SetIProcess,
|
||||
|
||||
@@ -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 <class T>
|
||||
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<T>& v) const{return val < v.val; }
|
||||
inline bool operator>(const T& v) const{return val > v; }
|
||||
inline bool operator>(const SAtomicVar<T>& v) const{return val > v.val; }
|
||||
inline bool operator<=(const T& v) const{return val <= v; }
|
||||
inline bool operator<=(const SAtomicVar<T>& v) const{return val <= v.val; }
|
||||
inline bool operator>=(const T& v) const{return val >= v; }
|
||||
inline bool operator>=(const SAtomicVar<T>& v) const{return val >= v.val; }
|
||||
inline bool operator==(const T& v) const{return val == v; }
|
||||
inline bool operator==(const SAtomicVar<T>& v) const{return val == v.val; }
|
||||
inline bool operator!=(const T& v) const{return val != v; }
|
||||
inline bool operator!=(const SAtomicVar<T>& 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<T>& v) volatile const{return val < v.val; }
|
||||
inline bool operator>(const T& v) volatile const{return val > v; }
|
||||
inline bool operator>(const SAtomicVar<T>& v) volatile const{return val > v.val; }
|
||||
inline bool operator<=(const T& v) volatile const{return val <= v; }
|
||||
inline bool operator<=(const SAtomicVar<T>& v) volatile const{return val <= v.val; }
|
||||
inline bool operator>=(const T& v) volatile const{return val >= v; }
|
||||
inline bool operator>=(const SAtomicVar<T>& v) volatile const{return val >= v.val; }
|
||||
inline bool operator==(const T& v) volatile const{return val == v; }
|
||||
inline bool operator==(const SAtomicVar<T>& v) volatile const{return val == v.val; }
|
||||
inline bool operator!=(const T& v) volatile const{return val != v; }
|
||||
inline bool operator!=(const SAtomicVar<T>& 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<int> TIntAtomic;
|
||||
typedef SAtomicVar<unsigned int> TUIntAtomic;
|
||||
typedef SAtomicVar<float> 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); }
|
||||
|
||||
@@ -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 T>
|
||||
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 <class Func>
|
||||
void sort(const Func& compare_less) { AutoLock lock(m_cs); std::sort(v.begin(), v.end(), compare_less); }
|
||||
|
||||
template <class Iter>
|
||||
void append(const Iter& startRange, const Iter& endRange) { AutoLock lock(m_cs); v.insert(v.end(), startRange, endRange); }
|
||||
|
||||
void swap(std::vector<T>& 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 <typename FindFunction, typename KeyType>
|
||||
bool find_and_copy(FindFunction findFunc, const KeyType& key, T& foundValue) const
|
||||
{
|
||||
AutoLock lock(m_cs);
|
||||
if (!v.empty())
|
||||
{
|
||||
typename std::vector<T>::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<T>::iterator it = std::find(v.begin(), v.end(), value);
|
||||
if (it != v.end())
|
||||
{
|
||||
v.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <typename Predicate>
|
||||
bool try_remove_and_erase_if(Predicate predicateFunction)
|
||||
{
|
||||
AutoLock lock(m_cs);
|
||||
if (!v.empty())
|
||||
{
|
||||
typename std::vector<T>::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<T>::iterator it = std::find(v.begin(), v.end(), value);
|
||||
if (it != v.end())
|
||||
{
|
||||
if (v.size() > 1)
|
||||
{
|
||||
typename std::vector<T>::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<T>& rOther)
|
||||
{
|
||||
AutoLock lock1(m_cs);
|
||||
AutoLock lock2(rOther.m_cs);
|
||||
|
||||
v = rOther.v;
|
||||
}
|
||||
|
||||
vector& operator=(const vector<T>& rOther)
|
||||
{
|
||||
if (this == &rOther)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
AutoLock lock1(m_cs);
|
||||
AutoLock lock2(rOther.m_cs);
|
||||
|
||||
v = rOther.v;
|
||||
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
std::vector<T> 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 T>
|
||||
class set
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T Key;
|
||||
typedef typename std::set<T>::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<value_type> 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 T, class Alloc = std::allocator<T> >
|
||||
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<T*, typename std::allocator_traits<Alloc>::template rebind_alloc<T*>> m_lockFreeQueue;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class Alloc>
|
||||
inline bool CLocklessPointerQueue<T, Alloc>::empty() const
|
||||
{
|
||||
return m_lockFreeQueue.empty();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class Alloc>
|
||||
inline void CLocklessPointerQueue<T, Alloc>::push(T* ptr)
|
||||
{
|
||||
m_lockFreeQueue.push(ptr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class Alloc>
|
||||
inline T* CLocklessPointerQueue<T, Alloc>::pop()
|
||||
{
|
||||
T* val = NULL;
|
||||
m_lockFreeQueue.try_pop(val);
|
||||
return val;
|
||||
}
|
||||
}; // namespace CryMT
|
||||
|
||||
namespace stl
|
||||
{
|
||||
template <typename T>
|
||||
void free_container(CryMT::vector<T>& v)
|
||||
{
|
||||
v.free_memory();
|
||||
}
|
||||
template <typename T>
|
||||
void free_container(CryMT::queue<T>& v)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -618,12 +618,6 @@ ILevel* CLevelSystem::LoadLevelInternal(const char* _levelName)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the camera to (1,1,1) (not (0,0,0) which is the invalid/uninitialised state,
|
||||
// to avoid the hack in the renderer to not show anything if the camera is at the origin).
|
||||
CCamera defaultCam;
|
||||
defaultCam.SetPosition(Vec3(1.0f));
|
||||
m_pSystem->SetViewCamera(defaultCam);
|
||||
|
||||
m_pLoadingLevelInfo = pLevelInfo;
|
||||
OnLoadingStart(levelName);
|
||||
|
||||
@@ -952,10 +946,6 @@ void CLevelSystem::UnloadLevel()
|
||||
oAudioRequestData.pData = &oAMData3;
|
||||
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequestBlocking, oAudioRequestData);
|
||||
|
||||
// Reset the camera to (0,0,0) which is the invalid/uninitialised state
|
||||
CCamera defaultCam;
|
||||
m_pSystem->SetViewCamera(defaultCam);
|
||||
|
||||
OnUnloadComplete(m_lastLevelName.c_str());
|
||||
|
||||
// -- kenzo: this will close all pack files for this level
|
||||
|
||||
@@ -268,12 +268,6 @@ namespace LegacyLevelSystem
|
||||
// This is a workaround until the replacement for GameEntityContext is done
|
||||
AzFramework::GameEntityContextEventBus::Broadcast(&AzFramework::GameEntityContextEventBus::Events::OnPreGameEntitiesStarted);
|
||||
|
||||
// Reset the camera to (1,1,1) (not (0,0,0) which is the invalid/uninitialised state,
|
||||
// to avoid the hack in the renderer to not show anything if the camera is at the origin).
|
||||
CCamera defaultCam;
|
||||
defaultCam.SetPosition(Vec3(1.0f));
|
||||
m_pSystem->SetViewCamera(defaultCam);
|
||||
|
||||
OnLoadingStart(levelName);
|
||||
|
||||
auto pPak = gEnv->pCryPak;
|
||||
@@ -587,10 +581,6 @@ namespace LegacyLevelSystem
|
||||
oAudioRequestData.pData = &oAMData3;
|
||||
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequestBlocking, oAudioRequestData);
|
||||
|
||||
// Reset the camera to (0,0,0) which is the invalid/uninitialised state
|
||||
CCamera defaultCam;
|
||||
m_pSystem->SetViewCamera(defaultCam);
|
||||
|
||||
OnUnloadComplete(m_lastLevelName.c_str());
|
||||
|
||||
AzFramework::RootSpawnableInterface::Get()->ReleaseRootSpawnable();
|
||||
|
||||
@@ -353,9 +353,6 @@ public:
|
||||
virtual IXmlUtils* GetXmlUtils();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SetViewCamera(CCamera& Camera){ m_ViewCamera = Camera; }
|
||||
CCamera& GetViewCamera() { return m_ViewCamera; }
|
||||
|
||||
void IgnoreUpdates(bool bIgnore) { m_bIgnoreUpdates = bIgnore; };
|
||||
|
||||
void SetIProcess(IProcess* process);
|
||||
@@ -494,7 +491,6 @@ private: // ------------------------------------------------------
|
||||
SSystemGlobalEnvironment m_env;
|
||||
|
||||
CTimer m_Time; //!<
|
||||
CCamera m_ViewCamera; //!<
|
||||
bool m_bInitializedSuccessfully; //!< true if the system completed all initialization steps
|
||||
bool m_bRelaunch; //!< relaunching the app or not (true beforerelaunch)
|
||||
int m_iLoadingMode; //!< Game is loading w/o changing context (0 not, 1 quickloading, 2 full loading)
|
||||
|
||||
@@ -896,16 +896,14 @@ void CSystem::InitLocalization()
|
||||
if (auto console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
|
||||
{
|
||||
AZ::CVarFixedString languageAudio;
|
||||
if (auto result = console->GetCvarValue("g_languageAudio", languageAudio); result == AZ::GetValueResult::Success)
|
||||
console->GetCvarValue("g_languageAudio", languageAudio);
|
||||
if (languageAudio.empty())
|
||||
{
|
||||
if (languageAudio.size() == 0)
|
||||
{
|
||||
console->PerformCommand(AZStd::string::format("g_languageAudio %s", language.c_str()).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
language.assign(languageAudio.data(), languageAudio.size());
|
||||
}
|
||||
console->PerformCommand(AZStd::string::format("g_languageAudio %s", language.c_str()).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
language.assign(languageAudio.data(), languageAudio.size());
|
||||
}
|
||||
}
|
||||
OpenLanguageAudioPak(language);
|
||||
|
||||
@@ -58,10 +58,10 @@ DebugCamera::~DebugCamera()
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void DebugCamera::OnEnable()
|
||||
{
|
||||
m_position = gEnv->pSystem->GetViewCamera().GetPosition();
|
||||
m_position = Vec3_Zero;
|
||||
m_moveInput = Vec3_Zero;
|
||||
|
||||
Ang3 cameraAngles = Ang3(gEnv->pSystem->GetViewCamera().GetMatrix());
|
||||
Ang3 cameraAngles = Ang3(ZERO);
|
||||
m_cameraYaw = RAD2DEG(cameraAngles.z);
|
||||
m_cameraPitch = RAD2DEG(cameraAngles.x);
|
||||
m_view = Matrix33(Ang3(DEG2RAD(m_cameraPitch), 0.0f, DEG2RAD(m_cameraYaw)));
|
||||
@@ -126,13 +126,6 @@ void DebugCamera::Update()
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void DebugCamera::PostUpdate()
|
||||
{
|
||||
if (m_cameraMode == DebugCamera::ModeOff)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CCamera& camera = gEnv->pSystem->GetViewCamera();
|
||||
camera.SetMatrix(Matrix34(m_view, m_position));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -55,79 +55,9 @@ void CView::Release()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CView::Update(float frameTime, bool isActive)
|
||||
void CView::Update([[maybe_unused]] float frameTime, [[maybe_unused]] bool isActive)
|
||||
{
|
||||
//FIXME:some cameras may need to be updated always
|
||||
if (!isActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_azEntity)
|
||||
{
|
||||
m_viewParams.SaveLast();
|
||||
|
||||
CCamera* pSysCam = &m_pSystem->GetViewCamera();
|
||||
|
||||
//process screen shaking
|
||||
ProcessShaking(frameTime);
|
||||
|
||||
//FIXME:to let the updateView implementation use the correct shakeVector
|
||||
m_viewParams.currentShakeShift = m_viewParams.rotation * m_viewParams.currentShakeShift;
|
||||
|
||||
m_viewParams.frameTime = frameTime;
|
||||
//update view position/rotation
|
||||
if (m_azEntity != nullptr)
|
||||
{
|
||||
auto entityTransform = m_azEntity->GetTransform();
|
||||
if (entityTransform != nullptr)
|
||||
{
|
||||
AZ::Transform transform = entityTransform->GetWorldTM();
|
||||
m_viewParams.position = AZVec3ToLYVec3(transform.GetTranslation());
|
||||
m_viewParams.rotation = AZQuaternionToLYQuaternion(transform.GetRotation());
|
||||
}
|
||||
}
|
||||
|
||||
ApplyFrameAdditiveAngles(m_viewParams.rotation);
|
||||
|
||||
const float fNearZ = gEnv->pSystem->GetIViewSystem()->GetDefaultZNear();
|
||||
|
||||
//see if the view have to use a custom near clipping plane
|
||||
const float nearPlane = (m_viewParams.nearplane >= CAMERA_MIN_NEAR) ? (m_viewParams.nearplane) : fNearZ;
|
||||
const float farPlane = (m_viewParams.farplane > 0.f) ? m_viewParams.farplane : DEFAULT_FAR;
|
||||
float fov = (m_viewParams.fov < 0.001f) ? DEFAULT_FOV : m_viewParams.fov;
|
||||
|
||||
m_camera.SetFrustum(pSysCam->GetViewSurfaceX(), pSysCam->GetViewSurfaceZ(), fov, nearPlane, farPlane, pSysCam->GetPixelAspectRatio());
|
||||
|
||||
//apply shake & set the view matrix
|
||||
m_viewParams.rotation *= m_viewParams.currentShakeQuat;
|
||||
m_viewParams.rotation.NormalizeSafe();
|
||||
m_viewParams.position += m_viewParams.currentShakeShift;
|
||||
|
||||
// Blending between cameras needs to happen after Camera space rendering calculations have been applied
|
||||
// so that the m_viewParams.position is in World Space again
|
||||
m_viewParams.UpdateBlending(frameTime);
|
||||
|
||||
// [VR] specific
|
||||
// Add HMD's pose tracking on top of current camera pose
|
||||
// Each game-title can decide whether to keep this functionality here or (most likely)
|
||||
// move it somewhere else.
|
||||
|
||||
Quat q = m_viewParams.rotation;
|
||||
Vec3 pos = m_viewParams.position;
|
||||
Vec3 p = Vec3(ZERO);
|
||||
|
||||
Matrix34 viewMtx(q);
|
||||
viewMtx.SetTranslation(pos + p);
|
||||
m_camera.SetMatrix(viewMtx);
|
||||
|
||||
m_camera.SetEntityRotation(m_viewParams.rotation);
|
||||
m_camera.SetEntityPos(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_linkedTo = AZ::EntityId(0);
|
||||
}
|
||||
AZ_ErrorOnce("CryLegacy", false, "CryLegacy view system no longer available (CView::Update)");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -253,7 +253,7 @@ void CViewSystem::Update(float frameTime)
|
||||
}
|
||||
}
|
||||
|
||||
m_pSystem->SetViewCamera(rCamera);
|
||||
AZ_ErrorOnce("CryLegacy", false, "CryLegacy view system no longer available (CViewSystem::Update)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,23 +557,7 @@ void CViewSystem::SetOverrideCameraRotation(bool bOverride, Quat rotation)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CViewSystem::UpdateSoundListeners()
|
||||
{
|
||||
assert(gEnv->IsEditor() && !gEnv->IsEditorGameMode());
|
||||
|
||||
// In Editor we may want to control global listeners outside of the game view.
|
||||
if (m_bControlsAudioListeners)
|
||||
{
|
||||
IView* const pActiveView = static_cast<IView*>(GetActiveView());
|
||||
TViewMap::const_iterator Iter(m_views.begin());
|
||||
TViewMap::const_iterator const IterEnd(m_views.end());
|
||||
|
||||
for (; Iter != IterEnd; ++Iter)
|
||||
{
|
||||
IView* const pView = Iter->second;
|
||||
bool const bIsActive = (pView == pActiveView);
|
||||
CCamera const& rCamera = bIsActive ? gEnv->pSystem->GetViewCamera() : pView->GetCamera();
|
||||
pView->UpdateAudioListener(rCamera.GetMatrix());
|
||||
}
|
||||
}
|
||||
AZ_ErrorOnce("CryLegacy", false, "CryLegacy view system no longer available (CViewSystem::UpdateSoundListeners)");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user