[*] Fix up modern WakeOnAddress fast path, of, well, WakeOnAddress

[*] Clean up AuEvent
[*] Dropped default spin power
This commit is contained in:
Reece Wilson 2023-03-13 23:57:32 +00:00
parent 2745ef23a0
commit 14c7d538e1
5 changed files with 92 additions and 48 deletions

View File

@ -335,7 +335,7 @@ namespace Aurora
{
bool bNoThreadNames { false };
bool bPlatformIsSMPProcessorOptimized { true }; // whether to attempt to using mm_pause or similar before yielding
AuUInt8 uSpinLoopPowerA { 16 }; // nudgable spinloop power
AuUInt8 uSpinLoopPowerA { 7 }; // nudgable spinloop power
};
struct RuntimeStartInfo

View File

@ -7,6 +7,7 @@
***/
#include <Source/RuntimeInternal.hpp>
#include "AuWakeOnAddress.hpp"
#include "Primitives/SMPYield.hpp"
namespace Aurora::Threading /*::Primitives for this file only!*/
{
@ -442,11 +443,11 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
return bResult;
}
AuTuple<const void *, AuUInt8, AuUInt32> DecodeAddress(const void *pAddress,
AuUInt32 uSizeMask)
AuTuple<const void *, AuUInt8, AuOptionalEx<AuUInt32>> DecodeAddress(const void *pAddress,
AuUInt32 uSizeMask)
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
return AuMakeTuple(pAddress, 0, 0xFFFFFFFF);
return AuMakeTuple(pAddress, 0, AuOptionalEx<AuUInt32> {});
#endif
auto pRounded = AuPageRound(AuUInt(pAddress), AuUInt(4));
@ -537,7 +538,36 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
}
else
{
return pWaitOnAddress((void *)pTargetAddress, (void *)pCompareAddress, uWordSize, uMS);
uMS = AuMin<AuUInt32>(uMS, 2000);
(void)pWaitOnAddress((void *)pTargetAddress, (void *)pCompareAddress, uWordSize, uMS);
if (!WaitBuffer::From(pCompareAddress, uWordSize).Compare(pTargetAddress))
{
return true;
}
AuUInt64 uNow {};
while (uAbsTime > (uNow = AuTime::SteadyClockNS()))
{
uMS = AuNSToMS<AuUInt32>(uAbsTime - uNow);
if (Primitives::DoTryIf([=]()
{
return !WaitBuffer::From(pCompareAddress, uWordSize).Compare(pTargetAddress);
}))
{
return true;
}
if (!uMS)
{
AuThreading::ContextYield();
}
else
{
(void)pWaitOnAddress((void *)pTargetAddress, (void *)pCompareAddress, uWordSize, uMS);
}
}
}
#endif
@ -579,20 +609,18 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
}
while (ret == EINTR);
return true;
#endif
return false;
return !WaitBuffer::From(pCompareAddress, uWordSize).Compare(pTargetAddress);
}
static void RunOSWaitOnAddressNoTimedNoErrors(const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize)
WaitState &state)
{
auto expect = WaitBuffer::From(pCompareAddress, uWordSize);
while (expect.Compare(pTargetAddress))
while (WaitBuffer::From(pTargetAddress, state.uWordSize).Compare(state))
{
if (!RunOSWaitOnAddressNoTimed(pTargetAddress, pCompareAddress, uWordSize))
if (!RunOSWaitOnAddressNoTimed(pTargetAddress, pCompareAddress, state.uWordSize))
{
AuThreading::ContextYield();
}
@ -601,17 +629,15 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
static bool RunOSWaitOnAddressTimedNoErrors(const void *pTargetAddress,
const void *pCompareAddress,
AuUInt8 uWordSize,
AuUInt64 qwNanoseconds)
WaitState &state)
{
auto expect = WaitBuffer::From(pCompareAddress, uWordSize);
if (!expect.Compare(pTargetAddress))
if (!WaitBuffer::From(pTargetAddress, state.uWordSize).Compare(state))
{
return true;
}
(void)RunOSWaitOnAddressTimed(pTargetAddress, pCompareAddress, uWordSize, AuTime::SteadyClockNS() + qwNanoseconds, qwNanoseconds);
return !expect.Compare(pTargetAddress);
(void)RunOSWaitOnAddressTimed(pTargetAddress, pCompareAddress, state.uWordSize, AuTime::SteadyClockNS() + state.qwNanoseconds.value(), state.qwNanoseconds.value());
return !WaitBuffer::From(pTargetAddress, state.uWordSize).Compare(state);
}
static void RunOSWakeNOnAddress(const void *pAddress,
@ -650,15 +676,23 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
{
auto [pWaitAddress, uDelta, uMask] = DecodeAddress(pTargetAddress, uWordSize);
auto pCompareAddress2 = AuReinterpretCast<char *>(pCompareAddress) - uDelta;
WaitState state;
state.uDownsizeMask = uMask;
state.compare = uMask ?
WaitBuffer::From(pCompareAddress2, 4) :
WaitBuffer::From(pCompareAddress2, uWordSize);
state.uWordSize = uMask ? 4 : uWordSize;
if (!qwNanoseconds)
{
RunOSWaitOnAddressNoTimedNoErrors(pWaitAddress, pCompareAddress2, uWordSize);
RunOSWaitOnAddressNoTimedNoErrors(pWaitAddress, pCompareAddress2, state);
return true;
}
else
{
return RunOSWaitOnAddressTimedNoErrors(pWaitAddress, pCompareAddress2, uWordSize, qwNanoseconds);
state.qwNanoseconds = qwNanoseconds;
return RunOSWaitOnAddressTimedNoErrors(pWaitAddress, pCompareAddress2, state);
}
}
else
@ -673,7 +707,10 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
void *pCompareAddress,
AuUInt8 uWordSize)
{
return !WaitBuffer::From(pCompareAddress, uWordSize).Compare(pTargetAddress);
return Primitives::DoTryIf([=]()
{
return !WaitBuffer::From(pCompareAddress, uWordSize).Compare(pTargetAddress);
});
}
AUKN_SYM void WakeNOnAddress(void *pTargetAddress,

View File

@ -31,6 +31,7 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
WaitBuffer compare;
AuOptionalEx<AuUInt64> qwNanoseconds;
AuOptionalEx<AuUInt32> uDownsizeMask;
AuUInt32 uWordSize {};
};
struct WaitEntry

View File

@ -12,9 +12,9 @@
namespace Aurora::Threading::Primitives
{
EventImpl::EventImpl(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers) :
triggered_(bTriggered),
atomicRelease_(bAtomicRelease),
permitMultipleTriggers_(bPermitMultipleTriggers),
bTriggered_(bTriggered),
bAtomicRelease_(bAtomicRelease),
bPermitMultipleTriggers_(bPermitMultipleTriggers),
condition_(AuUnsafeRaiiToShared(&this->mutex_))
{}
@ -25,23 +25,23 @@ namespace Aurora::Threading::Primitives
return true;
}
bool EventImpl::Lock(AuUInt64 timeout /*=0*/)
bool EventImpl::Lock(AuUInt64 uTimeout /*=0*/)
{
return LockNS(AuMSToNS<AuUInt64>(timeout));
return LockNS(AuMSToNS<AuUInt64>(uTimeout));
}
bool EventImpl::LockNS(AuUInt64 timeout /*=0*/)
bool EventImpl::LockNS(AuUInt64 uTimeout /*=0*/)
{
AU_LOCK_GUARD(this->mutex_);
AuInt64 uStartTime = Time::SteadyClockNS();
AuInt64 uEndTime = uStartTime + timeout;
AuInt64 uEndTime = uStartTime + uTimeout;
while (!AtomicIsEventSet())
while (!AtomicIsEventSetLogic())
{
AuUInt32 uTimeoutMs {};
if (timeout)
if (uTimeout)
{
uStartTime = Time::SteadyClockNS();
if (uStartTime >= uEndTime)
@ -66,9 +66,9 @@ namespace Aurora::Threading::Primitives
}
}
if (this->atomicRelease_)
if (this->bAtomicRelease_)
{
this->triggered_ = false;
this->bTriggered_ = false;
}
return true;
@ -76,16 +76,22 @@ namespace Aurora::Threading::Primitives
bool EventImpl::TryLock()
{
AU_LOCK_GUARD(mutex_);
AU_LOCK_GUARD(this->mutex_);
return AtomicIsEventSet();
return AtomicIsEventSetLogic();
}
bool EventImpl::AtomicIsEventSet()
bool EventImpl::AtomicIsEventSetLogic()
{
if (!this->triggered_) return false;
if (!this->bTriggered_)
{
return false;
}
if (this->atomicRelease_) this->triggered_ = false;
if (this->bAtomicRelease_)
{
this->bTriggered_ = false;
}
return true;
}
@ -93,15 +99,15 @@ namespace Aurora::Threading::Primitives
void EventImpl::Reset()
{
this->mutex_.Lock();
this->triggered_ = false;
this->bTriggered_ = false;
this->mutex_.Unlock();
}
void EventImpl::Set()
{
AU_LOCK_GUARD(this->mutex_);
SysAssertExp((this->permitMultipleTriggers_) || (!this->triggered_), "Can not trigger an awake event object");
this->triggered_ = true;
SysAssertExp((this->bPermitMultipleTriggers_) || (!this->bTriggered_), "Can not trigger an awake event object");
this->bTriggered_ = true;
this->condition_.Broadcast();
}
@ -124,7 +130,7 @@ namespace Aurora::Threading::Primitives
void EventImpl::Unlock()
{
// Unlike the other types, unlock is ways a nop
// Unlock is always a NOP; inverse of a lock/wait is nothing
}
AUKN_SYM IEvent *EventNew(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers)

View File

@ -12,10 +12,9 @@
namespace Aurora::Threading::Primitives
{
class EventImpl : public IEvent
struct EventImpl : IEvent
{
public:
EventImpl(bool trigged, bool atomicRelease, bool permitMultipleTriggers);
EventImpl(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers);
~EventImpl();
bool Init();
@ -31,12 +30,13 @@ namespace Aurora::Threading::Primitives
private:
bool AtomicIsEventSet();
bool AtomicIsEventSetLogic();
const bool atomicRelease_{};
const bool permitMultipleTriggers_{};
ConditionMutexImpl mutex_;
const bool bAtomicRelease_ {};
const bool bPermitMultipleTriggers_ {};
bool bTriggered_ {};
ConditionMutexImpl mutex_; // must come first
ConditionVariableImpl condition_;
bool triggered_;
};
}