/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuSemaphore.Linux.cpp Date: 2022-12-28 Author: Reece ***/ #include #include "AuSemaphore.Generic.hpp" #include "SMTYield.hpp" #if !defined(_AURUNTIME_GENERIC_SEMAPHORE) #include namespace Aurora::Threading::Primitives { SemaphoreImpl::SemaphoreImpl(long intialValue) : value_(intialValue) { } 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) { AuUInt64 uStart {}; AuUInt64 uEnd {}; if (this->TryLock()) { return true; } errno = 0; struct timespec tspec; if (uTimeout != 0) { uStart = AuTime::SteadyClockNS(); uEnd = uStart + uTimeout; Time::monoabsns2ts(&tspec, uEnd); } auto old = this->value_; //!tryLock (with old in a scope we can access) while (!((old != 0) && (AuAtomicCompareExchange(&this->value_, old - 1, old) == old))) { if (uTimeout != 0) { if (Time::SteadyClockNS() >= uEnd) { return false; } int ret {}; do { ret = futex_wait(&this->value_, 0, &tspec); } while (ret == EINTR); } else { int ret {}; bool bStatus {}; do { if ((ret = futex_wait(&this->value_, 0)) == 0) { bStatus = true; continue; } if (ret == EAGAIN || errno == EAGAIN) { bStatus = true; continue; } } while (ret == EINTR); RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "semaphore wait failed: {}", ret) } old = this->value_; } return true; } void SemaphoreImpl::Lock() { auto status = LockNS(0); SysAssert(status, "Couldn't lock semaphore"); } void SemaphoreImpl::Unlock(long count) { AuAtomicAdd(&this->value_, count); futex_wake(&this->value_, count); } void SemaphoreImpl::Unlock() { 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