[+] 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); LockMS(ms);
} }
virtual void Reset() = 0; virtual void Reset() = 0;
virtual void Set() = 0; virtual void Set() = 0;
virtual bool TrySet() = 0; // returns false on bPermitMultipleTriggers volation
}; };
AUKN_SHARED_SOO2_NCM(Event, IEvent, kPrimitiveSizeEvent, AUKN_SHARED_SOO2_NCM(Event, IEvent, kPrimitiveSizeEvent,

View File

@ -34,6 +34,11 @@ namespace Aurora::Threading::Primitives
AuInt64 uStartTime {}; AuInt64 uStartTime {};
AuInt64 uEndTime {}; AuInt64 uEndTime {};
if (AtomicIsEventSetLogicNoSpinNoLock())
{
return true;
}
if (uTimeout) if (uTimeout)
{ {
uStartTime = Time::SteadyClockNS(); uStartTime = Time::SteadyClockNS();
@ -42,7 +47,7 @@ namespace Aurora::Threading::Primitives
AU_LOCK_GUARD(this->mutex_); AU_LOCK_GUARD(this->mutex_);
while (!AtomicIsEventSetLogic()) while (!AtomicIsEventSetLogicNoSpinNoLock())
{ {
AuUInt32 uTimeoutNS {}; AuUInt32 uTimeoutNS {};
@ -68,41 +73,76 @@ namespace Aurora::Threading::Primitives
bool EventImpl::TryLock() bool EventImpl::TryLock()
{ {
AU_LOCK_GUARD(this->mutex_); return AtomicIsEventSetLogicNoSpinNoLock();
return AtomicIsEventSetLogic();
} }
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;
}
} }
else
if (this->bAtomicRelease_)
{ {
this->bTriggered_ = false; return bits.bTriggered;
} }
return true;
} }
void EventImpl::Reset() void EventImpl::Reset()
{ {
AU_LOCK_GUARD(this->mutex_); while (true)
this->bTriggered_ = false; {
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() void EventImpl::Set()
{ {
EventBits bits, next;
while (true)
{ {
AU_LOCK_GUARD(this->mutex_); bits.state = AuAtomicLoad(&this->state_);
SysAssertExp((this->bPermitMultipleTriggers_) || (!this->bTriggered_), "Can not trigger an awake event object");
this->bTriggered_ = true; // 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(); 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) bool EventImpl::HasOSHandle(AuMach &mach)
{ {
mach = 0; mach = 0;

View File

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