/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuSemaphore.NT.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuSemaphore.Generic.hpp" #include "AuSemaphore.NT.hpp" #include "SMTYield.hpp" #if !defined(_AURUNTIME_GENERIC_SEMAPHORE) namespace Aurora::Threading::Primitives { SemaphoreImpl::SemaphoreImpl(long iIntialValue) : var(AuUnsafeRaiiToShared(&this->mutex)) { this->value_ = iIntialValue; } SemaphoreImpl::~SemaphoreImpl() { } bool SemaphoreImpl::HasOSHandle(AuMach &mach) { return false; } bool SemaphoreImpl::HasLockImplementation() { return true; } bool SemaphoreImpl::TryLock() { return DoTryIf([=]() { auto old = this->value_; return (old != 0 && AuAtomicCompareExchange(&this->value_, old - 1, old) == old); }); } bool SemaphoreImpl::LockMS(AuUInt64 uTimeout) { return LockNS(AuMSToNS(uTimeout)); } bool SemaphoreImpl::LockNS(AuUInt64 uTimeout) { if (this->TryLock()) { return true; } AuUInt64 uStart = AuTime::SteadyClockNS(); AuUInt64 uEnd = uStart + uTimeout; if (pWaitOnAddress) { auto old = this->value_; //!tryLock (with old in a scope we can access) while (!((old != 0) && (AuAtomicCompareExchange(&this->value_, old - 1, old) == old))) { AuUInt32 dwTimeoutMs = INFINITE; if (uTimeout != 0) { uStart = Time::SteadyClockNS(); if (uStart >= uEnd) { return false; } dwTimeoutMs = AuNSToMS(uEnd - uStart); } old = 0; if (dwTimeoutMs == 0) { SMPPause(); AuThreading::ContextYield(); continue; } else { (void)pWaitOnAddress(&this->value_, &old, sizeof(this->value_), dwTimeoutMs); } old = this->value_; } return true; } else { this->mutex.Lock(); while (!TryLock()) { if (uTimeout != 0) { uStart = Time::SteadyClockNS(); if (uStart >= uEnd) { this->mutex.Unlock(); return false; } var.WaitForSignalNS(uEnd - uStart); } else { var.WaitForSignalNS(0); } } this->mutex.Unlock(); } return true; } void SemaphoreImpl::Lock() { auto status = LockNS(0); SysAssert(status, "Couldn't lock semaphore"); } void SemaphoreImpl::Unlock(long count) { if (!pWaitOnAddress) { this->mutex.Lock(); AuAtomicAdd(&this->value_, count); if (count == 1) { this->var.Signal(); } else { for (AU_ITERATE_N(i, count)) { (void)i; this->var.Signal(); } } this->mutex.Unlock(); } else { AuAtomicAdd(&this->value_, count); if (count == 1) { pWakeByAddressSingle(&this->value_); } else { pWakeByAddressAll(&this->value_); } } } void SemaphoreImpl::Unlock() { return Unlock(1); } AUKN_SYM ISemaphore *SemaphoreNew(int iInitialCount) { return _new SemaphoreImpl(iInitialCount); } AUKN_SYM void SemaphoreRelease(ISemaphore *pSemaphore) { AuSafeDelete(pSemaphore); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, Semaphore, SemaphoreImpl) } #endif