[*] Fix up modern WakeOnAddress fast path, of, well, WakeOnAddress
[*] Clean up AuEvent [*] Dropped default spin power
This commit is contained in:
parent
2745ef23a0
commit
14c7d538e1
@ -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
|
||||
|
@ -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,
|
||||
|
@ -31,6 +31,7 @@ namespace Aurora::Threading /*::Primitives for this file only!*/
|
||||
WaitBuffer compare;
|
||||
AuOptionalEx<AuUInt64> qwNanoseconds;
|
||||
AuOptionalEx<AuUInt32> uDownsizeMask;
|
||||
AuUInt32 uWordSize {};
|
||||
};
|
||||
|
||||
struct WaitEntry
|
||||
|
@ -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)
|
||||
|
@ -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_;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user