From bd94b73dde6e0ffd5fe9f480f7b0db2ff1a2f261 Mon Sep 17 00:00:00 2001 From: Reece Date: Sun, 30 Apr 2023 07:54:28 +0100 Subject: [PATCH] [+] New TLSView implementation [+] AuTLSVariable --- Include/Aurora/Runtime.hpp | 3 + .../Threading/Threads/IAuroraThread.hpp | 2 +- .../Aurora/Threading/Threads/TLSVariable.hpp | 107 ++++---- Include/Aurora/Threading/Threads/TLSView.hpp | 35 +-- Source/Threading/Threads/AuOSThread.cpp | 35 +-- Source/Threading/Threads/AuOSThread.hpp | 10 +- Source/Threading/Threads/AuThreadHandles.cpp | 2 +- Source/Threading/Threads/AuThreads.cpp | 7 +- Source/Threading/Threads/TLSView.cpp | 236 ++++++++++-------- Source/Threading/Threads/TLSView.hpp | 18 +- 10 files changed, 230 insertions(+), 225 deletions(-) diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index 563f8aba..5fb8f0d4 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -121,6 +121,9 @@ using AuMemoryViewWrite = AuMemory::MemoryViewWrite; using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead; using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite; +template +using AuTLSVariable = AuThreads::TLSVariable; + static bool AuIsThreadRunning() { return !AuThreads::GetThread()->Exiting(); diff --git a/Include/Aurora/Threading/Threads/IAuroraThread.hpp b/Include/Aurora/Threading/Threads/IAuroraThread.hpp index 2473cd7e..522063a1 100644 --- a/Include/Aurora/Threading/Threads/IAuroraThread.hpp +++ b/Include/Aurora/Threading/Threads/IAuroraThread.hpp @@ -19,7 +19,7 @@ namespace Aurora::HWInfo namespace Aurora::Threading::Threads { - class TLSView; + struct TLSView; /// Threads may be reimplemented as fibers or under some other userland context switcher /// Shared IAuroraThread objects maintain ownership of the execution of the context. diff --git a/Include/Aurora/Threading/Threads/TLSVariable.hpp b/Include/Aurora/Threading/Threads/TLSVariable.hpp index dd30186d..783e2092 100644 --- a/Include/Aurora/Threading/Threads/TLSVariable.hpp +++ b/Include/Aurora/Threading/Threads/TLSVariable.hpp @@ -11,86 +11,91 @@ namespace Aurora::Threading::Threads { AUKN_SYM bool DeadTest(); - template - class TLSVariable + template + struct TLSVariable { - private: - int _; - - public: - TLSVariable() {} + TLSVariable() + { + // NOP + } + ~TLSVariable() { - if constexpr (!isStatic) + #if 0 + if constexpr (!bIsStatic) + #endif { if (DeadTest()) { return; } - GetThread()->GetTlsView()->Remove(GetHandle()); + + TLSView::Remove(this->key); } } - - T& operator ->() + + T *operator ->() { - return Get(); + return &Get(); } - - operator T&() + + const T *operator ->() const { - return Get(); + return &Get(); } - - T operator *() + + operator T &() { return Get(); } - TLSVariable& operator =(const T & val) + operator const T &() const + { + return Get(); + } + + T operator *() const + { + return Get(); + } + + TLSVariable &operator =(const T &val) { Get() = val; return *this; } + TLSVariable &operator =(T &&val) + { + Get() = AuMove(val); + return *this; + } + private: + TLSKey key; - AuUInt64 GetHandle() + T &Get() const { - if constexpr (isStatic) + return *reinterpret_cast(TLSView::InitTLS(((TLSVariable *)this)->key, //const-ness isnt enforced here + sizeof(T), + [](void *buffer) -> void { - return (AuUInt64(reinterpret_cast(&_)) & (~kTlsKeyMask)) | kTlsKeyFollowsConvention | kTlsKeyStaticPointerHandle; - } - else + if constexpr (AuIsClass_v) + { + new (buffer) T(); + } + else + { + AuMemset(buffer, 0, sizeof(T)); + } + }, + [](void *buffer) -> void { - return (AuUInt64(reinterpret_cast(&_)) & (~kTlsKeyMask)) | kTlsKeyFollowsConvention | kTlsKeyResettablePointerHandle; - } - } - - T &Get() - { - auto view = GetThread()->GetTlsView(); - auto ptr = view->GetOrSetup(GetHandle(), - sizeof(T), - [](void *buffer) -> void + if constexpr (AuIsClass_v) { - if constexpr (AuIsClass_v) - { - new (buffer) T(); - } - else - { - //std::memset(buffer, 0, sizeof(T)); - } - }, - [](void *buffer) -> void - { - if constexpr (AuIsClass_v) - { - reinterpret_cast(buffer)->~T(); - } - }); - return *reinterpret_cast(ptr); + reinterpret_cast(buffer)->~T(); + } + })); } - }; } \ No newline at end of file diff --git a/Include/Aurora/Threading/Threads/TLSView.hpp b/Include/Aurora/Threading/Threads/TLSView.hpp index 99b79a35..440ac9d3 100644 --- a/Include/Aurora/Threading/Threads/TLSView.hpp +++ b/Include/Aurora/Threading/Threads/TLSView.hpp @@ -9,34 +9,17 @@ namespace Aurora::Threading::Threads { - static const AuUInt64 kTlsKeyFollowsConvention = AuUInt64(1) << AuUInt64(64 - 1); - static const AuUInt64 kTlsKeyStaticPointerHandle = AuUInt64(1) << AuUInt64(63 - 1); - static const AuUInt64 kTlsKeyResettablePointerHandle = AuUInt64(1) << AuUInt64(62 - 1); - static const AuUInt64 kTlsKeyMask = kTlsKeyResettablePointerHandle | kTlsKeyStaticPointerHandle | kTlsKeyFollowsConvention; - - class TLSView + struct TLSKey + { + Primitives::SpinLock lock; + void *pContext {}; + }; + + struct AUKN_SYM TLSView { - public: using TlsCb = AuFunction; - virtual void Remove(AuUInt64 key) = 0; - virtual void *GetTLS(AuUInt64 key, AuMach length, bool noAutoCreate = false) = 0; - virtual void *InitTLS(AuUInt64 key, AuMach length, const TlsCb &init, const TlsCb &deinit) = 0; - - void *GetOrSetup(AuUInt64 key, AuMach length, const TlsCb &init, const TlsCb &deinit) - { - void *tls; - #if 0 - if (!(tls = GetTLS(key, length, true))) - #endif - { - tls = InitTLS(key, length, init, deinit); - if (!tls) - { - return nullptr; - } - } - return tls; - } + static void Remove(TLSKey &key); + static void *InitTLS(TLSKey &key, AuMach length, const TlsCb &init, const TlsCb &deinit); }; } \ No newline at end of file diff --git a/Source/Threading/Threads/AuOSThread.cpp b/Source/Threading/Threads/AuOSThread.cpp index 25452427..06e1ee1a 100644 --- a/Source/Threading/Threads/AuOSThread.cpp +++ b/Source/Threading/Threads/AuOSThread.cpp @@ -82,22 +82,25 @@ namespace Aurora::Threading::Threads OSThread::OSThread(const ThreadInfo &info) : info_(info) { this->name_ = info.name.value_or("Aurora Thread"); - this->terminated_ = Primitives::EventShared(true, false, true); // maybe we should atomic exchange compare these when needed frogthink - this->terminateSignal_ = Primitives::EventShared(true, false, true); this->terminatedSignalLs_ = AuLoop::NewLSEvent(true, false, true); this->terminateSignalLs_ = AuLoop::NewLSEvent(true, false, true); - this->exitOnlyOnce_ = Primitives::CriticalSectionUnique(); - SysAssert(this->terminated_ ? true : false, "out of memory"); + this->terminated_ = AuThreadPrimitives::EventShared(true, false, true); + this->terminateSignal_ = AuThreadPrimitives::EventShared(true, false, true); + + SysAssert(this->terminatedSignalLs_ && this->terminateSignalLs_ && this->terminated_ && this->terminateSignal_); } OSThread::OSThread() : info_(gDummyThreadInfo) { this->name_ = "Main Thread"; - this->terminated_ = Primitives::EventShared(true, false); - this->exitOnlyOnce_ = Primitives::CriticalSectionUnique(); + + this->terminated_ = AuThreadPrimitives::EventShared(true, false, true); + this->terminateSignal_ = AuThreadPrimitives::EventShared(true, false, true); + + SysAssert(this->terminated_ && this->terminateSignal_); } OSThread::OSThread(AuUInt64 id) : info_(gDummyThreadInfo) @@ -155,7 +158,7 @@ namespace Aurora::Threading::Threads if (this->terminated_) { this->exiting_ = true; - if (WaitFor(this->terminated_.get(), 5000)) + if (this->terminated_->LockMS(5'000)) { return; } @@ -189,6 +192,7 @@ namespace Aurora::Threading::Threads AU_LOCK_GUARD(this->tlsLock_); AU_LOCK_GUARD(this->tlsReferenceThread_->tlsLock_); + SetThreadKey(this->tlsReferenceThread_->tls_); AuExchange(this->tlsReferenceThread_->tls_, this->tls_); AuExchange(this->tlsReferenceThread_->threadFeatures_, this->threadFeatures_); @@ -214,8 +218,7 @@ namespace Aurora::Threading::Threads // Is is expected for a system thread to release on dtor unlike our aurora threads void OSThread::HookReleaseThreadResources() { - tls_.reset(); - + AU_LOCK_GUARD(this->tlsLock_); for (const auto &feature : this->threadFeatures_) { feature->Cleanup(); @@ -224,7 +227,7 @@ namespace Aurora::Threading::Threads void OSThread::AddLastHopeTlsHook(const AuSPtr &feature) { - // TODO: mutex + AU_LOCK_GUARD(this->tlsLock_); if (!feature) { return; @@ -443,12 +446,7 @@ namespace Aurora::Threading::Threads AuSPtr OSThread::GetTlsView() { - if (!this->tls_) - { - this->tls_ = AuMakeShared(); - } - - return this->tls_; + SysPanic("Deprecated Concept"); } bool OSThread::ExecuteNewOSContext(AuFunction task) @@ -468,6 +466,11 @@ namespace Aurora::Threading::Threads AuThreading::ContextYield(); } + if (!this->tls_) + { + this->tls_ = GetThreadKey(); + } + this->_ThreadEP(); }, GetName(), this->info_.stackSize); diff --git a/Source/Threading/Threads/AuOSThread.hpp b/Source/Threading/Threads/AuOSThread.hpp index 4fbe5213..71b0a965 100644 --- a/Source/Threading/Threads/AuOSThread.hpp +++ b/Source/Threading/Threads/AuOSThread.hpp @@ -74,8 +74,8 @@ namespace Aurora::Threading::Threads #if defined(AURORA_IS_POSIX_DERIVED) jmp_buf env; #endif - Primitives::SpinLock tlsLock_; - AuSPtr tls_; + Primitives::Mutex tlsLock_; + AuUInt32 tls_ {}; OSThread * tlsReferenceThread_ {}; AuString name_; ThreadInfo info_; @@ -90,11 +90,11 @@ namespace Aurora::Threading::Threads bool contextUsed_{}; // can this thread instance execute code again? Primitives::EventShared_t terminated_; Primitives::EventShared_t terminateSignal_; - AuSPtr terminateSignalLs_; - AuSPtr terminatedSignalLs_; + AuSPtr terminateSignalLs_; + AuSPtr terminatedSignalLs_; bool bLongJmpOnce {}; - Primitives::CriticalSectionUnique_t exitOnlyOnce_; + Primitives::CriticalSection exitOnlyOnce_; AuList> threadFeatures_; diff --git a/Source/Threading/Threads/AuThreadHandles.cpp b/Source/Threading/Threads/AuThreadHandles.cpp index 40ff8662..c558b9e5 100644 --- a/Source/Threading/Threads/AuThreadHandles.cpp +++ b/Source/Threading/Threads/AuThreadHandles.cpp @@ -115,7 +115,7 @@ namespace Aurora::Threading::Threads #endif DEFINE_SPEEDY_TLS(OSFallbackThread, tlsOsFallbackThread); - DEFINE_SPEEDY_TLS(IAuroraThread*, tlsCurrentThread); + DEFINE_SPEEDY_TLS(IAuroraThread *, tlsCurrentThread); void HandleRemove() { diff --git a/Source/Threading/Threads/AuThreads.cpp b/Source/Threading/Threads/AuThreads.cpp index 1f14c243..a85de576 100644 --- a/Source/Threading/Threads/AuThreads.cpp +++ b/Source/Threading/Threads/AuThreads.cpp @@ -13,7 +13,12 @@ namespace Aurora::Threading::Threads { AUKN_SYM IAuroraThread *ThreadNew(const ThreadInfo &info) { - if (!info.callbacks) return {}; + if (!info.callbacks) + { + SysPushErrorArg(); + return {}; + } + return _new OSThread(info); } diff --git a/Source/Threading/Threads/TLSView.cpp b/Source/Threading/Threads/TLSView.cpp index 1ea06996..7ff34078 100644 --- a/Source/Threading/Threads/TLSView.cpp +++ b/Source/Threading/Threads/TLSView.cpp @@ -7,133 +7,153 @@ ***/ #include #include "TLSView.hpp" +#include "../Primitives/ThreadCookie.hpp" namespace Aurora::Threading::Threads { - void TLSViewImpl::Remove(AuUInt64 key) + static AuUInt32 uAtomicCounter {}; + static thread_local AuUInt32 tlsThreadIndex { }; + static const auto kMaxMaxLinearThreads = AuNumericLimits::max() / 2; + + AuUInt32 GetThreadKey() { - AU_LOCK_GUARD(lock_); + auto &uKey = tlsThreadIndex; - auto a = tls_.find(key); - if (a == tls_.end()) + if (!uKey) { - return; + uKey = AuAtomicAdd(&uAtomicCounter, 1u); + + if (uKey > kMaxMaxLinearThreads) [[unlikely]] + { + uKey = uAtomicCounter = kMaxMaxLinearThreads + 1; + } } - const auto &handler = a->second.second; - if (handler) - { - handler(a->second.first); - } - - tls_.erase(a); + return uKey; } - - TLSViewImpl::~TLSViewImpl() - { - for (const auto &itr : tls_) - { - const auto &handler = itr.second.second; - if (handler) - { - handler(itr.second.first); - } - } - - tls_.clear(); - } - - void *TLSViewImpl::GetTLS(AuUInt64 key, AuMach length, bool noAutoCreate) - { - AU_LOCK_GUARD(lock_); - AuPair*value; - - if (!length) - { - return nullptr; - } - - if (!AuTryFind(tls_, key, value)) - { - if (noAutoCreate) - { - return nullptr; - } - - auto buf = AuMemory::ZAlloc(length); - if (!buf) - { - return nullptr; - } - - auto ok = AuTryInsert(tls_, key, AuMakePair(buf, TlsCb {})); - if (!ok) - { - AuMemory::Free(buf); - return nullptr; - } - - ConsiderRehash(); - - return buf; - } - - return value->first; - } - - void *TLSViewImpl::InitTLS(AuUInt64 key, AuMach length, const TlsCb &init, const TlsCb &deinit) - { - AU_LOCK_GUARD(lock_); - AuPair*value; - - if (!length) - { - return nullptr; - } - - if (AuTryFind(tls_, key, value)) - { - return value->first; - } - - auto buf = AuMemory::ZAlloc(length); - if (!buf) - { - return nullptr; - } - - TlsCb deinitcb = deinit; - auto ok = AuTryInsert(tls_, key, AuMakePair(buf, deinitcb)); - if (!ok) - { - AuMemory::Free(buf); - return nullptr; - } - - ConsiderRehash(); - if (init) - { - init(buf); - } - - return buf; + void SetThreadKey(AuUInt32 uThreadKey) + { + tlsThreadIndex = uThreadKey; } - void TLSViewImpl::ConsiderRehash() + struct ViewEntry { - try + ~ViewEntry(); + + void *pVoid {}; + TLSView::TlsCb deinit; + }; + + struct ViewContext + { + // 256 bytes, less than some of microsofts stupid stl thread primitives + // so, ill take this as acceptable + /*void **/ ViewEntry table[32]; + + AuThreadPrimitives::Mutex mutex; + AuList> ptrs; + AuHashMap> hashMap; + + ViewEntry &GetHandleReference(); + }; + + ViewEntry::~ViewEntry() + { + if (this->pVoid && this->deinit) { - // prevent Add, Remove, Add, Remove stalls - fence_++; - if ((fence_ % 10) == 0) + this->deinit(this->pVoid); + } + } + + ViewEntry &ViewContext::GetHandleReference() + { + auto uKey = GetThreadKey(); + + if (uKey >= AuArraySize(this->table)) + { + AU_LOCK_GUARD(this->mutex); + + if (uKey > kMaxMaxLinearThreads) [[unlikely]] { - tls_.rehash(tls_.size()); + auto &sharedRef = this->hashMap[Primitives::GetThreadCookie()]; + if (!sharedRef) + { + sharedRef = AuMakeSharedPanic(); + } + + return *sharedRef.get(); + } + + uKey -= AuArraySize(this->table); + + if (uKey >= ptrs.size()) + { + ptrs.reserve(uKey * 2); + ptrs.resize(uKey); + } + + auto &sharedRef = ptrs[uKey]; + if (!sharedRef) + { + sharedRef = AuMakeSharedPanic(); + } + + return *sharedRef.get(); + } + else + { + return this->table[uKey]; + } + } + + void *TLSView::InitTLS(TLSKey &key, AuMach length, const TlsCb &init, const TlsCb &deinit) + { + ViewContext *pContext; + + if (!key.pContext) + { + AU_LOCK_GUARD(key.lock); + + if (key.pContext) + { + pContext = (ViewContext *)key.pContext; + } + else + { + key.pContext = pContext = new ViewContext(); } } - catch (...) + else { + pContext = (ViewContext *)key.pContext; + } + auto &refEntry = pContext->GetHandleReference(); + if (refEntry.pVoid) + { + return refEntry.pVoid; + } + else + { + refEntry.pVoid = AuMemory::_FAlloc(length, 64); + SysAssert(refEntry.pVoid, "TLS allocation failure"); + + if (init) + { + init(refEntry.pVoid); + } + + refEntry.deinit = deinit; + return refEntry.pVoid; + } + } + + void TLSView::Remove(TLSKey &key) + { + if (key.pContext) + { + delete (ViewContext *)key.pContext; } } } \ No newline at end of file diff --git a/Source/Threading/Threads/TLSView.hpp b/Source/Threading/Threads/TLSView.hpp index 731a629a..6dc65696 100644 --- a/Source/Threading/Threads/TLSView.hpp +++ b/Source/Threading/Threads/TLSView.hpp @@ -9,20 +9,6 @@ namespace Aurora::Threading::Threads { - class TLSViewImpl : public TLSView - { - public: - ~TLSViewImpl(); - - void Remove(AuUInt64 key) override; - void *GetTLS(AuUInt64 key, AuMach length, bool noAutoCreate) override; - void *InitTLS(AuUInt64 key, AuMach length, const TlsCb &init, const TlsCb &deinit) override; - - private: - void ConsiderRehash(); - - Primitives::SpinLock lock_; - AuHashMap> tls_; - AuUInt64 fence_ = 0; - }; + AuUInt32 GetThreadKey(); + void SetThreadKey(AuUInt32 uThreadKey); } \ No newline at end of file