2021-06-27 21:25:29 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
|
|
|
File: RWLock.cpp
|
|
|
|
Date: 2021-6-12
|
|
|
|
Author: Reece
|
|
|
|
***/
|
2021-09-30 14:57:41 +00:00
|
|
|
#include <Source/RuntimeInternal.hpp>
|
2021-06-27 21:25:29 +00:00
|
|
|
#include "RWLock.hpp"
|
|
|
|
|
|
|
|
namespace Aurora::Threading::Primitives
|
|
|
|
{
|
2021-10-08 19:51:34 +00:00
|
|
|
template<bool isread>
|
2021-10-02 16:07:33 +00:00
|
|
|
void RWLockAccessView<isread>::Unlock()
|
|
|
|
{
|
|
|
|
if constexpr (isread)
|
|
|
|
{
|
|
|
|
parent_.UnlockRead();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parent_.UnlockWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isread>
|
|
|
|
bool RWLockAccessView<isread>::Lock(AuUInt64 timeout)
|
|
|
|
{
|
|
|
|
if constexpr (isread)
|
|
|
|
{
|
|
|
|
return parent_.LockRead(timeout);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return parent_.LockWrite(timeout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isread>
|
|
|
|
bool RWLockAccessView<isread>::TryLock()
|
|
|
|
{
|
|
|
|
if constexpr (isread)
|
|
|
|
{
|
|
|
|
return parent_.TryLockRead();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return parent_.TryLockWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
RWLockImpl::RWLockImpl() : read_(*this), write_(*this)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
RWLockImpl::~RWLockImpl()
|
|
|
|
{
|
2021-06-30 09:28:52 +00:00
|
|
|
mutex_.reset();
|
|
|
|
condition_.reset();
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RWLockImpl::Init()
|
|
|
|
{
|
|
|
|
mutex_ = ConditionMutexUnique();
|
|
|
|
if (!mutex_)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-08 19:51:34 +00:00
|
|
|
condition_ = ConditionVariableUnique(AuUnsafeRaiiToShared(mutex_));
|
2021-06-27 21:25:29 +00:00
|
|
|
if (!condition_)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RWLockImpl::LockRead(AuUInt64 timeout)
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-30 09:28:52 +00:00
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
while (state_ < 0)
|
|
|
|
{
|
|
|
|
if (!condition_->WaitForSignal(timeout))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:33:58 +00:00
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2021-06-27 21:33:58 +00:00
|
|
|
state_++;
|
2021-06-27 21:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RWLockImpl::LockWrite(AuUInt64 timeout)
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-27 21:33:58 +00:00
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
while (state_ != 0)
|
|
|
|
{
|
|
|
|
if (!condition_->WaitForSignal(timeout))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-27 21:33:58 +00:00
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2021-06-27 21:33:58 +00:00
|
|
|
state_ = -1;
|
2021-06-27 21:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RWLockImpl::TryLockRead()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-27 21:33:58 +00:00
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
if (state_ == -1)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-27 21:33:58 +00:00
|
|
|
state_++;
|
2021-06-27 21:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RWLockImpl::TryLockWrite()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-27 21:33:58 +00:00
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
if (state_ > 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-27 21:33:58 +00:00
|
|
|
state_ = -1;
|
2021-06-27 21:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RWLockImpl::UnlockRead()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
auto val = --state_;
|
|
|
|
|
|
|
|
if ((val == 1) && (elevaterPending_))
|
|
|
|
{
|
|
|
|
condition_->Signal();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val == 0)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
condition_->Signal();
|
2021-06-27 21:33:58 +00:00
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RWLockImpl::UnlockWrite()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(mutex_);
|
2021-06-27 21:25:29 +00:00
|
|
|
state_ = 0;
|
|
|
|
condition_->Broadcast();
|
|
|
|
}
|
2021-09-06 10:58:08 +00:00
|
|
|
|
|
|
|
bool RWLockImpl::UpgradeReadToWrite(AuUInt64 timeout)
|
|
|
|
{
|
|
|
|
AU_LOCK_GUARD(mutex_);
|
|
|
|
|
|
|
|
while (state_ != 1)
|
|
|
|
{
|
|
|
|
elevaterPending_.store(true);
|
|
|
|
|
|
|
|
if (!condition_->WaitForSignal(timeout))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
elevaterPending_.store(false);
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
state_ = -1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
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<RWLockImpl *>(waitable);
|
|
|
|
}
|
2021-10-02 16:07:33 +00:00
|
|
|
}
|