[*] More compact Linux primitives
This commit is contained in:
parent
e8f445c463
commit
fa170c413d
@ -37,17 +37,17 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
static const auto kPrimitiveSize64LinuxMutex = 16;
|
||||
static const auto kPrimitiveSize64LinuxSemaphore = 16;
|
||||
static const auto kPrimitiveSize64LinuxCS = 40;
|
||||
static const auto kPrimitiveSize64LinuxEvent = 64;
|
||||
static const auto kPrimitiveSize64LinuxRWLock = 88;
|
||||
static const auto kPrimitiveSize64LinuxCS = 32;
|
||||
static const auto kPrimitiveSize64LinuxEvent = 32;
|
||||
static const auto kPrimitiveSize64LinuxRWLock = 64;
|
||||
static const auto kPrimitiveSize64LinuxCond = 32;
|
||||
static const auto kPrimitiveSize64LinuxCondMutex = 16;
|
||||
|
||||
// TODO: These values aren't quite correct yet:
|
||||
static const auto kPrimitiveSize32LinuxMutex = 12;
|
||||
static const auto kPrimitiveSize32LinuxSemaphore = 8;
|
||||
static const auto kPrimitiveSize32LinuxCS = 40;
|
||||
static const auto kPrimitiveSize32LinuxEvent = 40;
|
||||
static const auto kPrimitiveSize32LinuxSemaphore = 12;
|
||||
static const auto kPrimitiveSize32LinuxCS = 32;
|
||||
static const auto kPrimitiveSize32LinuxEvent = 32;
|
||||
static const auto kPrimitiveSize32LinuxRWLock = 88;
|
||||
static const auto kPrimitiveSize32LinuxCond = 32;
|
||||
static const auto kPrimitiveSize32LinuxCondMutex = 12;
|
||||
|
@ -27,6 +27,98 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
}
|
||||
|
||||
bool LinuxConditionMutex::LockMS(AuUInt64 uTimeout)
|
||||
{
|
||||
return LockNS(AuMSToNS<AuUInt64>(uTimeout));
|
||||
}
|
||||
|
||||
bool LinuxConditionMutex::LockNS(AuUInt64 uTimeout)
|
||||
{
|
||||
if (TryLockNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return LockNS(AuTime::SteadyClockNS() + uTimeout);
|
||||
}
|
||||
|
||||
bool LinuxConditionMutex::LockAbsMS(AuUInt64 uTimeout)
|
||||
{
|
||||
return LockAbsNS(AuMSToNS<AuUInt64>(uTimeout));
|
||||
}
|
||||
|
||||
bool LinuxConditionMutex::LockAbsNS(AuUInt64 uTimeout)
|
||||
{
|
||||
struct timespec tspec;
|
||||
|
||||
if (TryLockNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uTimeout != 0)
|
||||
{
|
||||
Time::monoabsns2ts(&tspec, uTimeout);
|
||||
}
|
||||
|
||||
if (TryLockHeavy())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AuAtomicAdd(&this->uSleeping_, 1u);
|
||||
|
||||
auto state = this->uState_;
|
||||
while (!(state == 0 &&
|
||||
AuAtomicCompareExchange<AuUInt32>(&this->uState_, 1, state) == state))
|
||||
{
|
||||
if (uTimeout != 0)
|
||||
{
|
||||
if (Time::SteadyClockNS() >= uTimeout)
|
||||
{
|
||||
AuAtomicSub(&this->uSleeping_, 1u);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret {};
|
||||
do
|
||||
{
|
||||
ret = futex_wait(&this->uState_, state, &tspec);
|
||||
}
|
||||
while (ret == EINTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxConditionMutex::TryLock()
|
||||
{
|
||||
if (gRuntimeConfig.threadingConfig.bPreferLinuxCondMutexSpinTryLock)
|
||||
@ -111,15 +203,15 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
AUKN_SYM IConditionMutex *ConditionMutexNew()
|
||||
{
|
||||
return _new LinuxConditionMutex();
|
||||
return _new ConditionMutexImpl();
|
||||
}
|
||||
|
||||
AUKN_SYM void ConditionMutexRelease(IConditionMutex *mutex)
|
||||
{
|
||||
AuSafeDelete<LinuxConditionMutex *>(mutex);
|
||||
AuSafeDelete<ConditionMutexImpl *>(mutex);
|
||||
}
|
||||
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, LinuxConditionMutex)
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, ConditionMutexImpl)
|
||||
}
|
||||
|
||||
#endif
|
@ -11,22 +11,56 @@
|
||||
|
||||
namespace Aurora::Threading::Primitives
|
||||
{
|
||||
struct LinuxConditionMutex final : IConditionMutexEx
|
||||
#pragma pack(push)
|
||||
#pragma pack(4)
|
||||
|
||||
struct LinuxConditionMutex final
|
||||
{
|
||||
LinuxConditionMutex();
|
||||
~LinuxConditionMutex();
|
||||
|
||||
bool TryLock() override;
|
||||
void Lock() override;
|
||||
void Unlock() override;
|
||||
AuUInt GetOSHandle() override;
|
||||
bool TryLock();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
AuUInt GetOSHandle();
|
||||
bool LockMS(AuUInt64 timeout);
|
||||
bool LockNS(AuUInt64 timeout);
|
||||
bool LockAbsMS(AuUInt64 timeout);
|
||||
bool LockAbsNS(AuUInt64 timeout);
|
||||
|
||||
auline bool TryLockNoSpin();
|
||||
auline bool TryLockHeavy();
|
||||
|
||||
private:
|
||||
AuUInt32 uState_ {};
|
||||
AuUInt32 uSleeping_ {};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
using ConditionMutexImpl = LinuxConditionMutex;
|
||||
using ConditionMutexInternal = LinuxConditionMutex;
|
||||
|
||||
struct ConditionMutexImpl final : IConditionMutexEx
|
||||
{
|
||||
auline bool TryLock()
|
||||
{
|
||||
return mutex.TryLock();
|
||||
}
|
||||
|
||||
auline void Lock()
|
||||
{
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
auline void Unlock()
|
||||
{
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
inline AuUInt GetOSHandle()
|
||||
{
|
||||
return mutex.GetOSHandle();
|
||||
}
|
||||
|
||||
ConditionMutexInternal mutex;
|
||||
};
|
||||
}
|
@ -25,5 +25,6 @@ namespace Aurora::Threading::Primitives
|
||||
pthread_mutex_t value_;
|
||||
};
|
||||
|
||||
using ConditionVariableInternal = UnixConditionMutex;
|
||||
using ConditionMutexImpl = UnixConditionMutex;
|
||||
}
|
@ -14,33 +14,17 @@
|
||||
|
||||
namespace Aurora::Threading::Primitives
|
||||
{
|
||||
ConditionVariableImpl::ConditionVariableImpl(const AuSPtr<IConditionMutex> &pMutex) :
|
||||
mutex_(AuStaticCast<LinuxConditionMutex>(pMutex))
|
||||
ConditionVariableLinux::ConditionVariableLinux()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
ConditionVariableLinux::~ConditionVariableLinux()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AuSPtr<IConditionMutex> ConditionVariableImpl::GetMutex()
|
||||
{
|
||||
return this->mutex_;
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitForSignal(AuUInt32 qwTimeoutRelative)
|
||||
{
|
||||
return WaitForSignalNS(AuMSToNS<AuUInt64>(qwTimeoutRelative));
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitForSignalNS(AuUInt64 qwTimeoutRelative)
|
||||
{
|
||||
return WaitForSignalNsEx(this->mutex_, qwTimeoutRelative);
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitOne(AuUInt64 qwTimeoutRelative)
|
||||
bool ConditionVariableLinux::WaitOne(AuUInt64 qwTimeoutRelative)
|
||||
{
|
||||
AuUInt64 uStart {};
|
||||
AuUInt64 uEnd {};
|
||||
@ -112,8 +96,8 @@ namespace Aurora::Threading::Primitives
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitForSignalNsEx(const std::shared_ptr<LinuxConditionMutex> &pMutex,
|
||||
AuUInt64 qwTimeoutRelative)
|
||||
bool ConditionVariableLinux::WaitForSignalNsEx(LinuxConditionMutex *pMutex,
|
||||
AuUInt64 qwTimeoutRelative)
|
||||
{
|
||||
|
||||
AuAtomicAdd(&this->uSleeping_, 1u);
|
||||
@ -149,7 +133,7 @@ namespace Aurora::Threading::Primitives
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
void ConditionVariableLinux::Signal()
|
||||
{
|
||||
AuUInt32 uWaitCount {};
|
||||
AuUInt32 uWaiters {};
|
||||
@ -173,7 +157,7 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Broadcast()
|
||||
void ConditionVariableLinux::Broadcast()
|
||||
{
|
||||
AuUInt32 uWaitCount {};
|
||||
AuUInt32 uWaiters {};
|
||||
|
@ -12,32 +12,69 @@
|
||||
|
||||
namespace Aurora::Threading::Primitives
|
||||
{
|
||||
struct ConditionVariableImpl final : IConditionVariable
|
||||
{
|
||||
ConditionVariableImpl(const AuSPtr<IConditionMutex> &mutex);
|
||||
~ConditionVariableImpl();
|
||||
#pragma pack(push)
|
||||
#pragma pack(4)
|
||||
|
||||
AuSPtr<IConditionMutex> GetMutex() override;
|
||||
bool WaitForSignal(AuUInt32 timeout) override;
|
||||
bool WaitForSignalNsEx(const std::shared_ptr<LinuxConditionMutex> &pMutex, AuUInt64 timeout);
|
||||
bool WaitForSignalNS(AuUInt64 qwTimeout) override;
|
||||
void Signal() override;
|
||||
void Broadcast() override;
|
||||
struct ConditionVariableLinux final
|
||||
{
|
||||
ConditionVariableLinux();
|
||||
~ConditionVariableLinux();
|
||||
|
||||
bool WaitForSignalNsEx(LinuxConditionMutex *pMutex, AuUInt64 timeout);
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
bool WaitOne(AuUInt64 qwTimeout);
|
||||
|
||||
private:
|
||||
AuUInt32 uState_ {};
|
||||
AuUInt32 uSleeping_ {};
|
||||
std::shared_ptr<LinuxConditionMutex> mutex_;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct CondVarDummy : IConditionVariable
|
||||
using ConditionVariableInternal = ConditionVariableLinux;
|
||||
|
||||
struct ConditionVariableImpl final : IConditionVariable
|
||||
{
|
||||
AuUInt32 uState_ {};
|
||||
AuUInt32 uSleeping_ {};
|
||||
inline ConditionVariableImpl(const AuSPtr<IConditionMutex> &mutex) :
|
||||
mutex(mutex)
|
||||
{
|
||||
}
|
||||
|
||||
auline AuSPtr<IConditionMutex> GetMutex() override
|
||||
{
|
||||
return mutex;
|
||||
}
|
||||
|
||||
auline bool WaitForSignal(AuUInt32 timeout) override
|
||||
{
|
||||
return cond.WaitForSignalNsEx(&std::static_pointer_cast<ConditionMutexImpl>(this->mutex)->mutex, AuMSToNS<AuUInt64>(timeout));
|
||||
}
|
||||
|
||||
auline bool WaitForSignalNS(AuUInt64 qwTimeout) override
|
||||
{
|
||||
return cond.WaitForSignalNsEx(&std::static_pointer_cast<ConditionMutexImpl>(this->mutex)->mutex, qwTimeout);
|
||||
}
|
||||
|
||||
inline bool WaitForSignalNsEx(const std::shared_ptr<LinuxConditionMutex> &pMutex, AuUInt64 timeout)
|
||||
{
|
||||
return cond.WaitForSignalNsEx(pMutex.get(), timeout);
|
||||
}
|
||||
|
||||
auline void Signal() override
|
||||
{
|
||||
cond.Signal();
|
||||
}
|
||||
|
||||
auline void Broadcast() override
|
||||
{
|
||||
cond.Broadcast();
|
||||
}
|
||||
|
||||
ConditionVariableInternal cond;
|
||||
std::shared_ptr<IConditionMutex> mutex;
|
||||
};
|
||||
|
||||
static const auto kSizeOfDummyCondVar = sizeof(CondVarDummy);
|
||||
static const auto kSizeOfDummyCondVar = sizeof(ConditionVariableInternal);
|
||||
|
||||
}
|
||||
#endif
|
@ -34,6 +34,8 @@ namespace Aurora::Threading::Primitives
|
||||
pthread_cond_t pthreadCv_;
|
||||
};
|
||||
|
||||
using ConditionVariableInternal = ConditionVariableImpl;
|
||||
|
||||
static const auto kSizeOfDummyCondVar = sizeof(CondVarDummy);
|
||||
|
||||
}
|
||||
|
@ -95,6 +95,48 @@ namespace Aurora::Threading::Primitives
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CriticalSectionImpl::LockAbsNS(AuUInt64 timeout)
|
||||
{
|
||||
auto cur = GetThreadCookie();
|
||||
|
||||
if (this->owner_ == cur)
|
||||
{
|
||||
this->count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->mutex_.LockAbsNS(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->owner_ = cur;
|
||||
this->count_ = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CriticalSectionImpl::LockAbsMS(AuUInt64 timeout)
|
||||
{
|
||||
auto cur = GetThreadCookie();
|
||||
|
||||
if (this->owner_ == cur)
|
||||
{
|
||||
this->count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->mutex_.LockAbsMS(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->owner_ = cur;
|
||||
this->count_ = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CriticalSectionImpl::Unlock()
|
||||
{
|
||||
if (--this->count_ == 0)
|
||||
|
@ -10,6 +10,10 @@
|
||||
#include "AuMutex.Generic.hpp"
|
||||
#include "ThreadCookie.hpp"
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
#include "AuConditionMutex.Linux.hpp"
|
||||
#endif
|
||||
|
||||
namespace Aurora::Threading::Primitives
|
||||
{
|
||||
struct CriticalSectionImpl final : IWaitable
|
||||
@ -23,10 +27,16 @@ namespace Aurora::Threading::Primitives
|
||||
void Lock() override;
|
||||
bool LockMS(AuUInt64 timeout) override;
|
||||
bool LockNS(AuUInt64 timeout) override;
|
||||
bool LockAbsMS(AuUInt64 timeout) override;
|
||||
bool LockAbsNS(AuUInt64 timeout) override;
|
||||
void Unlock() override;
|
||||
|
||||
private:
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
LinuxConditionMutex mutex_; // shave a few bytes
|
||||
#else
|
||||
MutexImpl mutex_;
|
||||
#endif
|
||||
ThreadCookie_t owner_;
|
||||
AuUInt32 count_;
|
||||
};
|
||||
|
@ -16,7 +16,6 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
SemaphoreImpl::SemaphoreImpl(AuUInt16 uIntialValue) : dwState_(uIntialValue)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SemaphoreImpl::~SemaphoreImpl()
|
||||
|
@ -49,7 +49,7 @@ namespace Aurora::Threading
|
||||
return;
|
||||
}
|
||||
|
||||
gRuntimeConfig.threadingConfig = decltype(gRuntimeConfig.threadingConfig)(*pUpdateConfig);
|
||||
gRuntimeConfig.threadingConfig = decltype(gRuntimeConfig.threadingConfig)(ThreadingConfig(*pUpdateConfig));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user