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