/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuRWLock.hpp Date: 2021-6-12 Author: Reece ***/ #pragma once #include "AuConditionVariable.Generic.hpp" #include "AuConditionMutex.Generic.hpp" #include "ThreadCookie.hpp" namespace Aurora::Threading::Primitives { template struct RWLockImpl; template struct RWLockAccessView : IWaitable { #if defined(RWLOCK_VIEW_HAS_PARENT) RWLockAccessView(T &impl) : parent_(impl) { } #endif bool LockMS(AuUInt64 timeout) override; bool LockNS(AuUInt64 timeout) override; bool LockAbsMS(AuUInt64 timeout) override; bool LockAbsNS(AuUInt64 timeout) override; bool TryLock() override; bool HasOSHandle(AuMach &mach) override { return false; } bool HasLockImplementation() override { return true; } void Lock() override { SysAssert(LockNS(0)); } void Unlock() override; private: #if defined(RWLOCK_VIEW_HAS_PARENT) T &parent_; #endif }; template struct RWLockImpl final : IRWLock { RWLockImpl(); ~RWLockImpl(); // i dont think i'll expose a high performance interface yet auline bool LockReadNSAbs(AuUInt64 timeout);// override; auline bool LockReadNS(AuUInt64 timeout);// override; auline bool LockWriteNS(AuUInt64 timeout);// override; auline bool LockWriteNSAbs(AuUInt64 timeout);// override; auline bool TryLockRead();// override; template auline bool TryLockReadNoSpin(); auline bool TryLockWriteScatterSwitch();// override; auline void UnlockRead();// override; auline void UnlockWrite();// override; auline void WriterWake(); auline bool WriterSleep(AuUInt64 qwTimeoutNS); auline bool WriterTryLock(); auline void FutexWriterWake(); auline bool TryLockWriteMaybeSpin();// override; auline bool TryLockWriteNoSpin();// override; auline bool LockWriteNSAbsUnlocked(AuUInt64 qwTimeoutNS);// override; bool UpgradeReadToWrite(AuUInt64 timeout) override; bool DowngradeWriteToRead() override; auline bool UpgradeReadToWriteDoUpgrade(); IWaitable *AsReadable() override; IWaitable *AsWritable() override; bool CheckSelfThreadIsWriter() override; auline ConditionVariableInternal &GetCondition(); auline ConditionVariableInternal &GetConditionWriter(); auline AuUInt32 *GetFutexCondition(); auline AuUInt32 *GetFutexConditionWriter(); auline void SignalOneReader(); auline void SignalOneWriter(); auline void SignalManyReader(); auline void SignalManyWriter(int iBias = 0); auline AuUInt32 *GetReadSleepCounter(); private: RWLockAccessView read_; RWLockAccessView write_; ConditionMutexInternal mutex_; #if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR) ConditionVariableInternal condition_; ConditionVariableInternal conditionWriter_; #else char conditionVariable_[kSizeOfDummyCondVar] {}; char conditionVariableWriter_[kSizeOfDummyCondVar] {}; #endif ThreadCookie_t reentrantWriteLockHandle_ {}; AuAInt32 iState_ {}; AuAInt32 dwWritersPending_ {}; public: cstatic const AuUInt8 kOffsetOfRead = AuOffsetOf(&RWLockImpl::read_); cstatic const AuUInt8 kOffsetOfWrite = AuOffsetOf(&RWLockImpl::write_); }; }