[+] IEvent::TrySet()

[+] New atomic logic for AuEvent. With this change, I can stop slandering it as the "shit primitive."
(it's still not the best it could be, but it's an improvement over what i had before)
This commit is contained in:
Reece Wilson 2023-09-10 14:00:18 +01:00
parent 12a2f30f47
commit 48dc2e790b
3 changed files with 126 additions and 24 deletions

View File

@ -27,8 +27,9 @@ namespace Aurora::Threading::Primitives
LockMS(ms);
}
virtual void Reset() = 0;
virtual void Set() = 0;
virtual void Reset() = 0;
virtual void Set() = 0;
virtual bool TrySet() = 0; // returns false on bPermitMultipleTriggers volation
};
AUKN_SHARED_SOO2_NCM(Event, IEvent, kPrimitiveSizeEvent,

View File

@ -34,6 +34,11 @@ namespace Aurora::Threading::Primitives
AuInt64 uStartTime {};
AuInt64 uEndTime {};
if (AtomicIsEventSetLogicNoSpinNoLock())
{
return true;
}
if (uTimeout)
{
uStartTime = Time::SteadyClockNS();
@ -42,7 +47,7 @@ namespace Aurora::Threading::Primitives
AU_LOCK_GUARD(this->mutex_);
while (!AtomicIsEventSetLogic())
while (!AtomicIsEventSetLogicNoSpinNoLock())
{
AuUInt32 uTimeoutNS {};
@ -68,41 +73,76 @@ namespace Aurora::Threading::Primitives
bool EventImpl::TryLock()
{
AU_LOCK_GUARD(this->mutex_);
return AtomicIsEventSetLogic();
return AtomicIsEventSetLogicNoSpinNoLock();
}
bool EventImpl::AtomicIsEventSetLogic()
bool EventImpl::AtomicIsEventSetLogicNoSpinNoLock()
{
if (!this->bTriggered_)
EventBits bits;
bits.state = AuAtomicLoad(&this->state_);
if (bits.bAtomicRelease)
{
return false;
if (bits.bTriggered)
{
auto next = bits;
next.bTriggered = 0;
return AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state;
}
else
{
return false;
}
}
if (this->bAtomicRelease_)
else
{
this->bTriggered_ = false;
return bits.bTriggered;
}
return true;
}
void EventImpl::Reset()
{
AU_LOCK_GUARD(this->mutex_);
this->bTriggered_ = false;
while (true)
{
EventBits bits, next;
bits.state = AuAtomicLoad(&this->state_);
if (!bits.bTriggered)
{
break;
}
next.state = bits.state;
next.bTriggered = 0;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state)
{
break;
}
}
}
void EventImpl::Set()
{
EventBits bits, next;
while (true)
{
AU_LOCK_GUARD(this->mutex_);
SysAssertExp((this->bPermitMultipleTriggers_) || (!this->bTriggered_), "Can not trigger an awake event object");
this->bTriggered_ = true;
bits.state = AuAtomicLoad(&this->state_);
// TODO: runtime config option to turn this into a handable exception
SysAssertExp((bits.bPermitMultipleTriggers) || (!bits.bTriggered), "Can not trigger an awake event object");
next.state = bits.state;
next.bTriggered = 1;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state)
{
break;
}
}
if (this->bAtomicRelease_)
this->mutex_.Lock();
this->mutex_.Unlock();
if (bits.bAtomicRelease)
{
this->condition_.Signal();
}
@ -112,6 +152,45 @@ namespace Aurora::Threading::Primitives
}
}
bool EventImpl::TrySet()
{
EventBits bits, next;
while (true)
{
bits.state = AuAtomicLoad(&this->state_);
if (!bits.bPermitMultipleTriggers)
{
if (bits.bTriggered)
{
return false;
}
}
next.state = bits.state;
next.bTriggered = 1;
if (AuAtomicCompareExchange(&this->state_, next.state, bits.state) == bits.state)
{
break;
}
}
this->mutex_.Lock();
this->mutex_.Unlock();
if (bits.bAtomicRelease)
{
this->condition_.Signal();
}
else
{
this->condition_.Broadcast();
}
return true;
}
bool EventImpl::HasOSHandle(AuMach &mach)
{
mach = 0;

View File

@ -23,13 +23,14 @@ namespace Aurora::Threading::Primitives
bool TryLock() override;
void Reset() override;
void Set() override;
bool TrySet() override;
bool HasOSHandle(AuMach &mach) override;
bool HasLockImplementation() override;
void Lock() override;
void Unlock() override;
private:
bool AtomicIsEventSetLogic();
bool AtomicIsEventSetLogicNoSpinNoLock();
ConditionMutexInternal mutex_; // must come first
ConditionVariableInternal condition_;
@ -39,9 +40,30 @@ namespace Aurora::Threading::Primitives
const bool bPermitMultipleTriggers_ {};
bool bTriggered_ {};
#else
AuUInt8 bAtomicRelease_ : 1;
AuUInt8 bPermitMultipleTriggers_ : 1;
AuUInt8 bTriggered_ : 1;
union EventBits
{
struct
{
AuUInt8 bAtomicRelease : 1;
AuUInt8 bPermitMultipleTriggers : 1;
AuUInt8 bTriggered : 1;
};
AuUInt8 state;
};
union
{
struct
{
AuUInt8 bAtomicRelease_ : 1;
AuUInt8 bPermitMultipleTriggers_ : 1;
AuUInt8 bTriggered_ : 1;
};
AuUInt8 state_;
};
#endif
};
}