/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuConditionMutex.Linux.cpp Date: 2023-8-11 Author: Reece ***/ #include #include "AuConditionMutex.Generic.hpp" #include "SMTYield.hpp" #if !defined(_AURUNTIME_GENERICCV) #include namespace Aurora::Threading::Primitives { #define barrier() __asm__ __volatile__("sfence": : :"memory") #define compilerReorderBarrier() __asm__ __volatile__("": : :"memory") LinuxConditionMutex::LinuxConditionMutex() { } LinuxConditionMutex::~LinuxConditionMutex() { } bool LinuxConditionMutex::TryLock() { if (gRuntimeConfig.threadingConfig.bPreferLinuxCondMutexSpinTryLock) { return TryLockHeavy(); } else { return TryLockNoSpin(); } } bool LinuxConditionMutex::TryLockNoSpin() { return AuAtomicTestAndSet(&this->uState_, 0) == 0; } bool LinuxConditionMutex::TryLockHeavy() { return DoTryIf([=]() { return TryLockNoSpin(); }); } void LinuxConditionMutex::Lock() { if (TryLockHeavy()) { return; } AuAtomicAdd(&this->uSleeping_, 1u); auto state = this->uState_; while (!(state == 0 && AuAtomicCompareExchange(&this->uState_, 1, state) == state)) { int ret {}; bool bStatus {}; do { if ((ret = futex_wait(&this->uState_, state)) == 0) { bStatus = true; break; } if (ret == EAGAIN || errno == EAGAIN) { bStatus = true; break; } } while (ret == EINTR); RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "Mutex wait failed: {}", ret) state = this->uState_; } AuAtomicSub(&this->uSleeping_, 1u); } void LinuxConditionMutex::Unlock() { __sync_lock_release(&this->uState_); compilerReorderBarrier(); if (this->uSleeping_) { futex_wake(&this->uState_, 1); } } AuUInt LinuxConditionMutex::GetOSHandle() { return AuMach(&this->uState_); } AUKN_SYM IConditionMutex *ConditionMutexNew() { return _new LinuxConditionMutex(); } AUKN_SYM void ConditionMutexRelease(IConditionMutex *mutex) { AuSafeDelete(mutex); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, LinuxConditionMutex) } #endif