[*] Updated bit utilities

[*] Updated default string type
[*] Spinlocks can now timeout
[*] Finish RW lock write entrant mode
This commit is contained in:
Reece Wilson 2022-02-18 17:39:01 +00:00
parent fac6571504
commit 749b8deb8d
7 changed files with 99 additions and 25 deletions

View File

@ -359,8 +359,8 @@ namespace Aurora::Memory
// String API
inline bool WriteString(const AuString &string, EStringType type, Locale::ECodePage codepage = Locale::ECodePage::eUTF8);
inline bool ReadString(AuString &string, EStringType type, Locale::ECodePage codepage = Locale::ECodePage::eUTF8);
inline bool WriteString(const AuString &string, EStringType type = EStringType::eStringDword, Locale::ECodePage codepage = Locale::ECodePage::eUTF8);
inline bool ReadString(AuString &string, EStringType type = EStringType::eStringDword, Locale::ECodePage codepage = Locale::ECodePage::eUTF8);
// Copy, concat, etc
inline bool WriteFrom(ByteBuffer &buffer, AuUInt length);

View File

@ -26,11 +26,7 @@ namespace Aurora::Threading::Primitives
void Unlock() override;
private:
#if defined(_AU_HAS_ATOMIC_INTRINS)
volatile AuAtomicInt value_;
#else
std::atomic_long value_;
#endif
AuAtomicInt value_;
};
AUKN_SHARED_API(SpinLock, SpinLock);

View File

@ -10,9 +10,30 @@
template<typename T>
struct AuAtomicUtils
{
/**
* @brief Sets bit offset in in
* @return original value
*/
static T Set(T *in, AuUInt8 offset);
/**
* @brief Adds addend to in
* @return updated value
*/
static T Add(T *in, T addend);
/**
* @brief Subtracts the minuend from in
* @return updated value
*/
static T Sub(T *in, T minuend);
/**
* @brief Generic bitwise compare exchange
* @param replace replacement value for in if in matches compare
* @param compare required reference value
* @return original value
*/
static T CompareExchange(T *in, T replace, T compare);
};
@ -129,6 +150,36 @@ inline auline AuUInt16 AuAtomicUtils<AuUInt16>::Set(AuUInt16 *in, AuUInt8 offset
}
template<>
inline auline AuInt64 AuAtomicUtils<AuInt64>::Set(AuInt64 *in, AuUInt8 offset)
{
return _InterlockedOr64(reinterpret_cast<long long volatile *>(in), AuUInt64(1) << offset);
}
template<>
inline auline AuInt32 AuAtomicUtils<AuInt32>::Set(AuInt32 *in, AuUInt8 offset)
{
return _InterlockedOr(reinterpret_cast<long volatile *>(in), 1 << offset);
}
template<>
inline auline long AuAtomicUtils<long>::Set(long *in, AuUInt8 offset)
{
return _InterlockedOr(reinterpret_cast<long volatile *>(in), 1 << offset);
}
template<>
inline auline unsigned long AuAtomicUtils<unsigned long>::Set(unsigned long *in, AuUInt8 offset)
{
return _InterlockedOr(reinterpret_cast<long volatile *>(in), 1 << offset);
}
template<>
inline auline AuInt16 AuAtomicUtils<AuInt16>::Set(AuInt16 *in, AuUInt8 offset)
{
return _InterlockedOr16(reinterpret_cast<short volatile *>(in), 1 << offset);
}
#elif defined(AURORA_COMPILER_CLANG) || defined(AURORA_COMPILER_GCC)
template<typename T>
@ -152,7 +203,7 @@ inline auline T AuAtomicUtils<T>::Sub(T *in, T minuend)
template<typename T>
inline auline T AuAtomicUtils<T>::Set(T *in, AuUInt8 offset)
{
return __sync_or_and_fetch(in, T(1) << offset);
return __sync_fetch_and_or(in, T(1) << offset);
}
#endif

View File

@ -53,6 +53,12 @@ inline AuUInt32 AuEndianUtils<AuUInt32>::Swap(AuUInt32 in)
return _byteswap_ulong(in);
}
template<>
inline unsigned long AuEndianUtils<unsigned long>::Swap(unsigned long in)
{
return _byteswap_ulong(in);
}
template<>
inline AuUInt16 AuEndianUtils<AuUInt16>::Swap(AuUInt16 in)
{

View File

@ -127,13 +127,12 @@ namespace Aurora::Threading::Primitives
bool RWLockImpl::TryLockRead()
{
AU_LOCK_GUARD(mutex_);
if (this->state_ == -1)
{
return this->reentrantWriteLockHandle_ == AuThreads::GetThreadId();
}
AU_LOCK_GUARD(mutex_);
this->state_++;
return true;
}
@ -147,6 +146,7 @@ namespace Aurora::Threading::Primitives
return false;
}
this->reentrantWriteLockHandle_ = AuThreads::GetThreadId();
this->state_ = -1;
return true;
}

View File

@ -48,17 +48,21 @@ namespace Aurora::Threading::Primitives
AcquireSRWLockShared(&lock_); // we use atomics. using shared is fine, let's not get congested early
while (!TryLock())
{
start = AuTime::CurrentInternalClockMS();
AuUInt32 timeoutMs = INFINITE;
if (end <= start)
if (timeout != 0)
{
ReleaseSRWLockShared(&lock_);
return false;
start = Time::CurrentClockMS();
if (start >= end)
{
ReleaseSRWLockShared(&lock_);
return false;
}
timeoutMs = end - start;
}
auto timeout = end - start;
if (!::SleepConditionVariableSRW(&winCond_, &lock_, AuUInt32(timeout), CONDITION_VARIABLE_LOCKMODE_SHARED))
if (!::SleepConditionVariableSRW(&winCond_, &lock_, AuUInt32(timeoutMs), CONDITION_VARIABLE_LOCKMODE_SHARED))
{
ReleaseSRWLockShared(&lock_);
return false;

View File

@ -54,16 +54,33 @@ namespace Aurora::Threading::Primitives
bool SpinLock::Lock(AuUInt64 timeout)
{
#if defined(_AU_HAS_ATOMIC_INTRINS)
while (_interlockedbittestandset(&value_, 0))
#else
while (value_.fetch_or(1))
#endif
if (timeout == 0)
{
long count = 0;
while (value_)
while (AuAtomicSet(&this->value_, 0))
{
YieldCpu(count);
long count = 0;
while (value_)
{
YieldCpu(count);
}
}
}
else
{
AuUInt64 startTime = AuTime::CurrentInternalClockMS();
AuUInt64 endTime = startTime + timeout;
while (AuAtomicSet(&this->value_, 0))
{
long count = 0;
while (value_)
{
if (endTime <= AuTime::CurrentInternalClockMS())
{
return false;
}
YieldCpu(count);
}
}
}