291 lines
5.4 KiB
C++
291 lines
5.4 KiB
C++
#include "skse64/GameTypes.h"
|
|
|
|
BSString::~BSString()
|
|
{
|
|
if (m_data)
|
|
{
|
|
Heap_Free(m_data);
|
|
m_data = NULL;
|
|
}
|
|
}
|
|
|
|
const char * BSString::Get(void) const
|
|
{
|
|
return m_data ? m_data : "";
|
|
}
|
|
|
|
StringCache::Ref::Ref()
|
|
{
|
|
CALL_MEMBER_FN(this, ctor)("");
|
|
}
|
|
|
|
|
|
StringCache::Ref::Ref(const char * buf)
|
|
{
|
|
CALL_MEMBER_FN(this, ctor)(buf);
|
|
}
|
|
|
|
void SimpleLock::Lock(UInt32 pauseAttempts)
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
_mm_lfence();
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockCount);
|
|
}
|
|
else
|
|
{
|
|
UInt32 attempts = 0;
|
|
if (InterlockedCompareExchange(&lockCount, 1, 0))
|
|
{
|
|
do
|
|
{
|
|
++attempts;
|
|
_mm_pause();
|
|
if (attempts >= pauseAttempts) {
|
|
UInt32 spinCount = 0;
|
|
while (InterlockedCompareExchange(&lockCount, 1, 0))
|
|
Sleep(++spinCount < kFastSpinThreshold ? 0 : 1);
|
|
break;
|
|
}
|
|
} while (InterlockedCompareExchange(&lockCount, 1, 0));
|
|
_mm_lfence();
|
|
}
|
|
|
|
threadID = myThreadID;
|
|
_mm_sfence();
|
|
}
|
|
}
|
|
|
|
void SimpleLock::Release(void)
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
_mm_lfence();
|
|
if (threadID == myThreadID)
|
|
{
|
|
if (lockCount == 1)
|
|
{
|
|
threadID = 0;
|
|
_mm_mfence();
|
|
InterlockedCompareExchange(&lockCount, 0, 1);
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&lockCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** using runtime internal implementation rather than our reimplementation so it can be hooked by other plugins
|
|
|
|
void BSReadWriteLock::LockForRead()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockValue);
|
|
}
|
|
else
|
|
{
|
|
UInt32 lockCount = lockValue & kLockCountMask;
|
|
UInt32 spinCount = 0;
|
|
UInt32 lockResult = InterlockedCompareExchange(&lockValue, lockCount + 1, lockCount);
|
|
while (lockResult != lockCount + 1)
|
|
{
|
|
if ((lockResult & kLockWrite) != 0)
|
|
{
|
|
Sleep(++spinCount < kFastSpinThreshold ? 0 : 1);
|
|
lockResult = lockValue;
|
|
}
|
|
|
|
lockCount = lockValue & kLockCountMask;
|
|
lockResult = InterlockedCompareExchange(&lockValue, lockCount + 1, lockCount);
|
|
}
|
|
|
|
threadID = myThreadID;
|
|
}
|
|
}
|
|
|
|
void BSReadWriteLock::LockForWrite()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockValue);
|
|
}
|
|
else
|
|
{
|
|
UInt32 spinCount = 0;
|
|
while (InterlockedCompareExchange(&lockValue, UInt32(1 | kLockWrite), 0) != UInt32(1 | kLockWrite))
|
|
Sleep(++spinCount < kFastSpinThreshold ? 0 : 1);
|
|
|
|
threadID = myThreadID;
|
|
_mm_mfence();
|
|
}
|
|
}
|
|
|
|
void BSReadWriteLock::LockForReadAndWrite()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockValue);
|
|
}
|
|
else
|
|
{
|
|
UInt32 spinCount = 0;
|
|
while (InterlockedCompareExchange(&lockValue, 1, 0) != 1)
|
|
Sleep(++spinCount >= kFastSpinThreshold ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
bool BSReadWriteLock::TryLockForWrite()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
bool result = false;
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockValue);
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
result = InterlockedCompareExchange(&lockValue, UInt32(1 | kLockWrite), 0) == UInt32(1 | kLockWrite);
|
|
if (result)
|
|
{
|
|
threadID = myThreadID;
|
|
_mm_mfence();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
bool BSReadWriteLock::TryLockForRead()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
|
|
bool result = false;
|
|
if (threadID == myThreadID)
|
|
{
|
|
InterlockedIncrement(&lockValue);
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
UInt32 lockCount = lockValue & kLockCountMask;
|
|
UInt32 lockResult = InterlockedCompareExchange(&lockValue, lockCount + 1, lockCount);
|
|
while ((lockResult & kLockWrite) == 0)
|
|
{
|
|
if (lockResult == lockCount)
|
|
break;
|
|
|
|
lockCount = lockResult & kLockCountMask;
|
|
lockResult = InterlockedCompareExchange(&lockValue, lockCount + 1, lockCount);
|
|
}
|
|
|
|
result = ~(lockResult >> 31) & 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void BSReadWriteLock::Unlock()
|
|
{
|
|
SInt32 myThreadID = GetCurrentThreadId();
|
|
if (threadID == myThreadID)
|
|
{
|
|
UInt32 lockCount = lockValue - 1;
|
|
if (lockValue == kLockWrite)
|
|
{
|
|
threadID = 0;
|
|
_mm_mfence();
|
|
InterlockedExchange(&lockValue, 0);
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&lockValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&lockValue);
|
|
}
|
|
}*/
|
|
|
|
void UpdateRegistrationHolder::Order(UInt32 index)
|
|
{
|
|
UInt32 count = m_regs.count;
|
|
UInt32 pivotIndex = count >> 1;
|
|
|
|
if (index >= pivotIndex)
|
|
return;
|
|
|
|
Registration * pOldReg = m_regs[index];
|
|
UInt32 startIndex = index;
|
|
UInt32 cmpIndex;
|
|
do
|
|
{
|
|
cmpIndex = 2 * index + 1;
|
|
|
|
if (cmpIndex < (count - 1))
|
|
{
|
|
Registration * pCur = m_regs[cmpIndex];
|
|
Registration * pSucc = m_regs[cmpIndex + 1];
|
|
if (!pCur || !pSucc || pCur->schedTime > pSucc->schedTime)
|
|
cmpIndex++;
|
|
}
|
|
|
|
Registration * pCmpReg = m_regs[cmpIndex];
|
|
if (!pCmpReg || !pOldReg || pCmpReg->schedTime > pOldReg->schedTime)
|
|
break;
|
|
|
|
m_regs[index] = pCmpReg;
|
|
index = cmpIndex;
|
|
|
|
} while (cmpIndex < pivotIndex);
|
|
|
|
if (index != startIndex)
|
|
m_regs[index] = pOldReg;
|
|
|
|
}
|
|
|
|
bool UpdateRegistrationHolder::Remove(UInt64 & handle)
|
|
{
|
|
if (m_regs.count == 0)
|
|
return false;
|
|
|
|
for (UInt32 i = 0; i<m_regs.count; i++)
|
|
{
|
|
Registration * pReg = m_regs[i];
|
|
|
|
if (pReg && pReg->handle == handle)
|
|
{
|
|
UInt32 lastIndex = m_regs.count - 1;
|
|
|
|
// Remove last entry => no reorganizing necessary
|
|
if (i == lastIndex)
|
|
{
|
|
pReg->Release();
|
|
m_regs.count--;
|
|
}
|
|
else
|
|
{
|
|
m_regs[i] = m_regs[lastIndex];
|
|
m_regs[lastIndex] = pReg; // seems pointless, but the original code does it
|
|
|
|
pReg->Release();
|
|
m_regs.count--;
|
|
|
|
Order(i);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|