/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Event.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuEvent.hpp" #include "SMPYield.hpp" namespace Aurora::Threading::Primitives { EventImpl::EventImpl(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers) : triggered_(bTriggered), atomicRelease_(bAtomicRelease), permitMultipleTriggers_(bPermitMultipleTriggers), condition_(AuUnsafeRaiiToShared(&this->mutex_)) {} EventImpl::~EventImpl() {} bool EventImpl::Init() { return true; } bool EventImpl::Lock(AuUInt64 timeout /*=0*/) { return LockNS(AuMSToNS(timeout)); } bool EventImpl::LockNS(AuUInt64 timeout /*=0*/) { AU_LOCK_GUARD(this->mutex_); AuInt64 uStartTime = Time::SteadyClockNS(); AuInt64 uEndTime = uStartTime + timeout; while (!AtomicIsEventSet()) { AuUInt32 uTimeoutMs {}; if (timeout) { uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { return false; } uTimeoutMs = AuNSToMS(uEndTime - uStartTime); if (!uTimeoutMs) { this->mutex_.Unlock(); SMPPause(); AuThreading::ContextYield(); this->mutex_.Lock(); continue; } } if (!this->condition_.WaitForSignal(uTimeoutMs)) { continue; } } if (this->atomicRelease_) { this->triggered_ = false; } return true; } bool EventImpl::TryLock() { AU_LOCK_GUARD(mutex_); return AtomicIsEventSet(); } bool EventImpl::AtomicIsEventSet() { if (!this->triggered_) return false; if (this->atomicRelease_) this->triggered_ = false; return true; } void EventImpl::Reset() { this->mutex_.Lock(); this->triggered_ = 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; this->condition_.Broadcast(); } bool EventImpl::HasOSHandle(AuMach &mach) { mach = 0; return false; } bool EventImpl::HasLockImplementation() { return true; } void EventImpl::Lock() { auto ok = Lock(0); SysAssert(ok); } void EventImpl::Unlock() { // Unlike the other types, unlock is ways a nop } AUKN_SYM IEvent *EventNew(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers) { auto event = _new EventImpl(bTriggered, bAtomicRelease, bPermitMultipleTriggers); if (!event) { return nullptr; } if (!event->Init()) { EventRelease(event); return nullptr; } return event; } AUKN_SYM void EventRelease(IEvent *pEvent) { AuSafeDelete(pEvent); } }