Cross-platform atomic operations. (#44)

* Cross-platform spin lock implementation.

* Cross-platform reference counting.
This commit is contained in:
Skyth (Asilkan) 2024-12-16 12:20:51 +03:00 committed by GitHub
parent 5642576cea
commit 4770e85573
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 13 deletions

View file

@ -44,22 +44,26 @@ namespace Hedgehog::Base
inline void SStringHolder::AddRef() inline void SStringHolder::AddRef()
{ {
std::atomic_ref atomicRef(RefCountAndLength.value);
uint32_t originalValue, incrementedValue; uint32_t originalValue, incrementedValue;
do do
{ {
originalValue = RefCountAndLength.value; originalValue = RefCountAndLength.value;
incrementedValue = ByteSwap(ByteSwap(originalValue) + 1); incrementedValue = ByteSwap(ByteSwap(originalValue) + 1);
} while (InterlockedCompareExchange(reinterpret_cast<LONG*>(&RefCountAndLength), incrementedValue, originalValue) != originalValue); } while (!atomicRef.compare_exchange_weak(originalValue, incrementedValue));
} }
inline void SStringHolder::Release() inline void SStringHolder::Release()
{ {
std::atomic_ref atomicRef(RefCountAndLength.value);
uint32_t originalValue, decrementedValue; uint32_t originalValue, decrementedValue;
do do
{ {
originalValue = RefCountAndLength.value; originalValue = RefCountAndLength.value;
decrementedValue = ByteSwap(ByteSwap(originalValue) - 1); decrementedValue = ByteSwap(ByteSwap(originalValue) - 1);
} while (InterlockedCompareExchange(reinterpret_cast<LONG*>(&RefCountAndLength), decrementedValue, originalValue) != originalValue); } while (!atomicRef.compare_exchange_weak(originalValue, decrementedValue));
if (RefCountAndLength == 0) if (RefCountAndLength == 0)
__HH_FREE(this); __HH_FREE(this);

View file

@ -28,22 +28,26 @@ namespace boost
void add_ref() void add_ref()
{ {
std::atomic_ref useCount(use_count_.value);
be<uint32_t> original, incremented; be<uint32_t> original, incremented;
do do
{ {
original = use_count_; original = use_count_;
incremented = original + 1; incremented = original + 1;
} while (InterlockedCompareExchange((unsigned long*)&use_count_, incremented.value, original.value) != original.value); } while (!useCount.compare_exchange_weak(original.value, incremented.value));
} }
void release() void release()
{ {
std::atomic_ref useCount(use_count_.value);
be<uint32_t> original, decremented; be<uint32_t> original, decremented;
do do
{ {
original = use_count_; original = use_count_;
decremented = original - 1; decremented = original - 1;
} while (InterlockedCompareExchange((unsigned long*)&use_count_, decremented.value, original.value) != original.value); } while (!useCount.compare_exchange_weak(original.value, decremented.value));
if (decremented == 0) if (decremented == 0)
{ {
@ -54,12 +58,14 @@ namespace boost
void weak_release() void weak_release()
{ {
std::atomic_ref weakCount(weak_count_.value);
be<uint32_t> original, decremented; be<uint32_t> original, decremented;
do do
{ {
original = weak_count_; original = weak_count_;
decremented = original - 1; decremented = original - 1;
} while (InterlockedCompareExchange((unsigned long*)&weak_count_, decremented.value, original.value) != original.value); } while (!weakCount.compare_exchange_weak(original.value, decremented.value));
if (decremented == 0) if (decremented == 0)
{ {

View file

@ -84,22 +84,26 @@ struct GuestResource
void AddRef() void AddRef()
{ {
std::atomic_ref atomicRef(refCount.value);
uint32_t originalValue, incrementedValue; uint32_t originalValue, incrementedValue;
do do
{ {
originalValue = refCount.value; originalValue = refCount.value;
incrementedValue = ByteSwap(ByteSwap(originalValue) + 1); incrementedValue = ByteSwap(ByteSwap(originalValue) + 1);
} while (InterlockedCompareExchange(reinterpret_cast<LONG*>(&refCount), incrementedValue, originalValue) != originalValue); } while (!atomicRef.compare_exchange_weak(originalValue, incrementedValue));
} }
void Release() void Release()
{ {
std::atomic_ref atomicRef(refCount.value);
uint32_t originalValue, decrementedValue; uint32_t originalValue, decrementedValue;
do do
{ {
originalValue = refCount.value; originalValue = refCount.value;
decrementedValue = ByteSwap(ByteSwap(originalValue) - 1); decrementedValue = ByteSwap(ByteSwap(originalValue) - 1);
} while (InterlockedCompareExchange(reinterpret_cast<LONG*>(&refCount), decrementedValue, originalValue) != originalValue); } while (!atomicRef.compare_exchange_weak(originalValue, decrementedValue));
// Normally we are supposed to release here, so only use this // Normally we are supposed to release here, so only use this
// function when you know you won't be the one destructing it. // function when you know you won't be the one destructing it.

View file

@ -695,15 +695,22 @@ void RtlRaiseException_x()
void KfReleaseSpinLock(uint32_t* spinLock) void KfReleaseSpinLock(uint32_t* spinLock)
{ {
InterlockedExchange((volatile long*)spinLock, 0); std::atomic_ref spinLockRef(*spinLock);
spinLockRef = 0;
} }
void KfAcquireSpinLock(uint32_t* spinLock) void KfAcquireSpinLock(uint32_t* spinLock)
{ {
const auto ctx = GetPPCContext(); std::atomic_ref spinLockRef(*spinLock);
while (true)
{
uint32_t expected = 0;
if (spinLockRef.compare_exchange_weak(expected, g_ppcContext->r13.u32))
break;
while (InterlockedCompareExchange((volatile long*)spinLock, ByteSwap(*(uint32_t*)(g_memory.Translate(ctx->r13.u32 + 0x110))), 0) != 0)
std::this_thread::yield(); std::this_thread::yield();
}
} }
uint64_t KeQueryPerformanceFrequency() uint64_t KeQueryPerformanceFrequency()
@ -735,15 +742,22 @@ void VdGetSystemCommandBuffer()
void KeReleaseSpinLockFromRaisedIrql(uint32_t* spinLock) void KeReleaseSpinLockFromRaisedIrql(uint32_t* spinLock)
{ {
InterlockedExchange((volatile long*)spinLock, 0); std::atomic_ref spinLockRef(*spinLock);
spinLockRef = 0;
} }
void KeAcquireSpinLockAtRaisedIrql(uint32_t* spinLock) void KeAcquireSpinLockAtRaisedIrql(uint32_t* spinLock)
{ {
const auto ctx = GetPPCContext(); std::atomic_ref spinLockRef(*spinLock);
while (true)
{
uint32_t expected = 0;
if (spinLockRef.compare_exchange_weak(expected, g_ppcContext->r13.u32))
break;
while (InterlockedCompareExchange((volatile long*)spinLock, ByteSwap(*(uint32_t*)(g_memory.Translate(ctx->r13.u32 + 0x110))), 0) != 0)
std::this_thread::yield(); std::this_thread::yield();
}
} }
uint32_t KiApcNormalRoutineNop() uint32_t KiApcNormalRoutineNop()