[+] Aurora::Threading::TryWaitOnAddressEx

[*] Spin on top of Linuxs kernel spin, if in non-emu mode
This commit is contained in:
Reece Wilson 2023-11-14 14:44:56 +00:00
parent 3225d8cbda
commit 62e8625a11
7 changed files with 72 additions and 33 deletions

View File

@ -381,7 +381,7 @@ namespace Aurora
AuUInt64 bPreferEmulatedWakeOnAddress : 1 { !AuBuild::kIsNtDerived /*everybody else requires us to hit the kernel. */ };
#endif
AuUInt64 bPreferWaitOnAddressAlwaysSpin : 1 { false }; // ..., if emulated! if double-spinning under higher level locks, disable me.
AuUInt64 bPreferWaitOnAddressAlwaysSpinNative : 1 { false }; // ..., if not emulated! noting that most kernels and user-schedulers will spin for you
AuUInt64 bPreferWaitOnAddressAlwaysSpinNative : 1 { !AuBuild::kIsNtDerived }; // ..., if not emulated! noting that most kernels and user-schedulers will spin for you
AuUInt64 bPreferRWLockReadLockSpin : 1 { true };
AuUInt64 bUWPNanosecondEmulationCheckFirst : 1 { false };
AuUInt64 uUWPNanosecondEmulationMaxYields : 7 { 12 };

View File

@ -83,15 +83,21 @@ namespace Aurora::Threading::Waitables
}
}
if (this->TryChkNoSpin())
while (!this->TryChkNoSpin())
{
if (TryWaitOnAddressEx((const void *)&this->uAtomicState,
&kRef,
sizeof(kRef),
[&](const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)
{
return this->TryChkNoSpin();
}))
{
return true;
}
(void)TryWaitOnAddress((const void *)&this->uAtomicState, &kRef, sizeof(kRef));
while (!this->TryChkNoSpin())
{
if (!WaitOnAddressSteady((const void *)&this->uAtomicState, &kRef, sizeof(kRef), uTimeoutAbsNS))
{
if (this->TryChkNoSpin())

View File

@ -179,19 +179,22 @@ namespace Aurora::Threading::Waitables
auline bool TryLock2()
{
static const AuUInt32 kRef { 0 };
if (TryLock3())
{
return true;
}
static const AuUInt32 kRef { 0 };
if (TryWaitOnAddress((const void *)&this->uAtomicState, &kRef, sizeof(kRef)))
return TryWaitOnAddressEx((const void *)&this->uAtomicState,
&kRef,
sizeof(kRef),
[&](const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)
{
return TryLock3();
}
return false;
return this->TryLock3();
});
}
auline bool SleepOne(AuUInt64 qwTimeout)

View File

@ -27,18 +27,22 @@ namespace Aurora::Threading::Waitables
inline bool TryLock() override
{
static const AuUInt32 kRef { 0 };
if (TryLockNoSpin())
{
return true;
}
static const AuUInt32 kRef { 0 };
if (TryWaitOnAddress((const void *)&this->uAtomicState, &kRef, sizeof(kRef)))
return TryWaitOnAddressEx((const void *)&this->uAtomicState,
&kRef,
sizeof(kRef),
[&](const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)
{
return TryLockNoSpin();
}
return false;
return this->TryLockNoSpin();
});
}
inline bool HasOSHandle(AuMach &mach) override

View File

@ -26,21 +26,22 @@ namespace Aurora::Threading::Waitables
inline bool TryLock() override
{
if (TryLockNoSpin())
{
return true;
}
static const AuUInt32 kRef { 1 };
if (TryWaitOnAddress((const void *)&this->uAtomicState, &kRef, sizeof(kRef)))
{
if (TryLockNoSpin())
{
return true;
}
}
return false;
return TryWaitOnAddressEx((const void *)&this->uAtomicState,
&kRef,
sizeof(kRef),
[&](const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)
{
return this->TryLockNoSpin();
});
}
inline bool HasOSHandle(AuMach &mach) override

View File

@ -39,6 +39,11 @@ namespace Aurora::Threading
const void *pCompareAddress,
AuUInt8 uWordSize);
AUKN_SYM bool TryWaitOnAddressEx(const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize,
const AuFunction<bool(const void *, const void *, AuUInt8)> &check);
// Relative timeout variant of nanosecond resolution WoA. 0 = indefinite
AUKN_SYM bool WaitOnAddress(const void *pTargetAddress,
const void *pCompareAddress,

View File

@ -903,10 +903,30 @@ namespace Aurora::Threading
const void *pCompareAddress,
AuUInt8 uWordSize)
{
auto expect = WaitBuffer::From(pCompareAddress, uWordSize);
return Primitives::DoTryIf([&]()
{
return !expect.Compare(pTargetAddress);
return !WaitBuffer::Compare(pCompareAddress, uWordSize, pTargetAddress);
});
}
AUKN_SYM bool TryWaitOnAddressEx(const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize,
const AuFunction<bool(const void *, const void *, AuUInt8)> &check)
{
if (!check)
{
return TryWaitOnAddress(pTargetAddress, pCompareAddress, uWordSize);
}
return Primitives::DoTryIf([&]()
{
if (WaitBuffer::Compare(pCompareAddress, uWordSize, pTargetAddress))
{
return false;
}
return check(pTargetAddress, pCompareAddress, uWordSize);
});
}