/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: RWLock.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "RWLock.hpp" namespace Aurora::Threading::Primitives { RWLockImpl::RWLockImpl() : read_(*this), write_(*this) { } RWLockImpl::~RWLockImpl() { mutex_.reset(); condition_.reset(); } bool RWLockImpl::Init() { mutex_ = ConditionMutexUnique(); if (!mutex_) { return false; } condition_ = ConditionVariableUnique(mutex_.get()); if (!condition_) { return false; } return true; } bool RWLockImpl::LockRead(AuUInt64 timeout) { AU_LOCK_GUARD(mutex_); while (state_ < 0) { if (!condition_->WaitForSignal(timeout)) { return false; } } state_++; return true; } bool RWLockImpl::LockWrite(AuUInt64 timeout) { AU_LOCK_GUARD(mutex_); while (state_ != 0) { if (!condition_->WaitForSignal(timeout)) { return false; } } state_ = -1; return true; } bool RWLockImpl::TryLockRead() { AU_LOCK_GUARD(mutex_); if (state_ == -1) { return false; } state_++; return true; } bool RWLockImpl::TryLockWrite() { AU_LOCK_GUARD(mutex_); if (state_ > 0) { return false; } state_ = -1; return true; } void RWLockImpl::UnlockRead() { AU_LOCK_GUARD(mutex_); auto val = --state_; if ((val == 1) && (elevaterPending_)) { condition_->Signal(); } if (val == 0) { condition_->Signal(); } } void RWLockImpl::UnlockWrite() { AU_LOCK_GUARD(mutex_); state_ = 0; condition_->Broadcast(); } bool RWLockImpl::UpgradeReadToWrite(AuUInt64 timeout) { AU_LOCK_GUARD(mutex_); while (state_ != 1) { elevaterPending_.store(true); if (!condition_->WaitForSignal(timeout)) { return false; } } elevaterPending_.store(false); state_ = -1; return true; } IWaitable *RWLockImpl::AsReadable() { return &read_; } IWaitable *RWLockImpl::AsWritable() { return &write_; } AUKN_SYM RWLock *RWLockNew() { auto ret = _new RWLockImpl(); if (!ret) { return nullptr; } if (!ret->Init()) { delete ret; return nullptr; } return ret; } AUKN_SYM void RWLockRelease(RWLock *waitable) { SafeDelete(waitable); } }