[+] 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:
parent
12a2f30f47
commit
48dc2e790b
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user