/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuSpinLock.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuSpinLock.hpp" #include "SMPYield.hpp" namespace Aurora::Threading::Primitives { static void YieldCpu(long &count) { int loops = (1 << count); while (loops > 0) { SMPPause(); loops -= 1; } count++; if (count >= 15) count = 0; } SpinLock::SpinLock() { value_ = 0; } bool SpinLock::HasOSHandle(AuMach &mach) { return false; } bool SpinLock::TryLock() { return AuAtomicTestAndSet(&this->value_, 0) == 0; } bool SpinLock::HasLockImplementation() { return true; } void SpinLock::Lock() { auto status = Lock(0); SysAssert(status, "Couldn't lock Mutex object"); } bool SpinLock::LockNS(AuUInt64 timeout) { if (timeout == 0) { while (AuAtomicTestAndSet(&this->value_, 0)) { long count = 0; while (this->value_) { YieldCpu(count); } } } else { AuUInt64 startTime = AuTime::HighResClockNS(); AuUInt64 endTime = startTime + timeout; while (AuAtomicTestAndSet(&this->value_, 0)) { long count = 0; while (value_) { if (endTime <= AuTime::HighResClockNS()) { return false; } YieldCpu(count); } } } return true; } bool SpinLock::Lock(AuUInt64 timeout) { return LockNS(AuMSToNS(timeout)); } void SpinLock::Unlock() { this->value_ = 0; } }