[+] New TLSView implementation
[+] AuTLSVariable
This commit is contained in:
parent
37472e508e
commit
bd94b73dde
@ -121,6 +121,9 @@ using AuMemoryViewWrite = AuMemory::MemoryViewWrite;
|
|||||||
using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead;
|
using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead;
|
||||||
using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite;
|
using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite;
|
||||||
|
|
||||||
|
template<typename T, bool bIsStatic = false>
|
||||||
|
using AuTLSVariable = AuThreads::TLSVariable<T, bIsStatic>;
|
||||||
|
|
||||||
static bool AuIsThreadRunning()
|
static bool AuIsThreadRunning()
|
||||||
{
|
{
|
||||||
return !AuThreads::GetThread()->Exiting();
|
return !AuThreads::GetThread()->Exiting();
|
||||||
|
@ -19,7 +19,7 @@ namespace Aurora::HWInfo
|
|||||||
|
|
||||||
namespace Aurora::Threading::Threads
|
namespace Aurora::Threading::Threads
|
||||||
{
|
{
|
||||||
class TLSView;
|
struct TLSView;
|
||||||
|
|
||||||
/// Threads may be reimplemented as fibers or under some other userland context switcher
|
/// Threads may be reimplemented as fibers or under some other userland context switcher
|
||||||
/// Shared IAuroraThread objects maintain ownership of the execution of the context.
|
/// Shared IAuroraThread objects maintain ownership of the execution of the context.
|
||||||
|
@ -11,86 +11,91 @@ namespace Aurora::Threading::Threads
|
|||||||
{
|
{
|
||||||
AUKN_SYM bool DeadTest();
|
AUKN_SYM bool DeadTest();
|
||||||
|
|
||||||
template<typename T, bool isStatic = false>
|
template<typename T, bool bIsStatic = false>
|
||||||
class TLSVariable
|
struct TLSVariable
|
||||||
{
|
{
|
||||||
private:
|
TLSVariable()
|
||||||
int _;
|
{
|
||||||
|
// NOP
|
||||||
public:
|
}
|
||||||
TLSVariable() {}
|
|
||||||
~TLSVariable()
|
~TLSVariable()
|
||||||
{
|
{
|
||||||
if constexpr (!isStatic)
|
#if 0
|
||||||
|
if constexpr (!bIsStatic)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (DeadTest())
|
if (DeadTest())
|
||||||
{
|
{
|
||||||
return;
|
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();
|
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;
|
Get() = val;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TLSVariable &operator =(T &&val)
|
||||||
|
{
|
||||||
|
Get() = AuMove(val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
TLSKey key;
|
||||||
|
|
||||||
AuUInt64 GetHandle()
|
T &Get() const
|
||||||
{
|
{
|
||||||
if constexpr (isStatic)
|
return *reinterpret_cast<T *>(TLSView::InitTLS(((TLSVariable *)this)->key, //const-ness isnt enforced here
|
||||||
|
sizeof(T),
|
||||||
|
[](void *buffer) -> void
|
||||||
{
|
{
|
||||||
return (AuUInt64(reinterpret_cast<AuUInt>(&_)) & (~kTlsKeyMask)) | kTlsKeyFollowsConvention | kTlsKeyStaticPointerHandle;
|
if constexpr (AuIsClass_v<T>)
|
||||||
}
|
{
|
||||||
else
|
new (buffer) T();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AuMemset(buffer, 0, sizeof(T));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](void *buffer) -> void
|
||||||
{
|
{
|
||||||
return (AuUInt64(reinterpret_cast<AuUInt>(&_)) & (~kTlsKeyMask)) | kTlsKeyFollowsConvention | kTlsKeyResettablePointerHandle;
|
if constexpr (AuIsClass_v<T>)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T &Get()
|
|
||||||
{
|
|
||||||
auto view = GetThread()->GetTlsView();
|
|
||||||
auto ptr = view->GetOrSetup(GetHandle(),
|
|
||||||
sizeof(T),
|
|
||||||
[](void *buffer) -> void
|
|
||||||
{
|
{
|
||||||
if constexpr (AuIsClass_v<T>)
|
reinterpret_cast<T *>(buffer)->~T();
|
||||||
{
|
}
|
||||||
new (buffer) T();
|
}));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//std::memset(buffer, 0, sizeof(T));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[](void *buffer) -> void
|
|
||||||
{
|
|
||||||
if constexpr (AuIsClass_v<T>)
|
|
||||||
{
|
|
||||||
reinterpret_cast<T *>(buffer)->~T();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return *reinterpret_cast<T *>(ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -9,34 +9,17 @@
|
|||||||
|
|
||||||
namespace Aurora::Threading::Threads
|
namespace Aurora::Threading::Threads
|
||||||
{
|
{
|
||||||
static const AuUInt64 kTlsKeyFollowsConvention = AuUInt64(1) << AuUInt64(64 - 1);
|
struct TLSKey
|
||||||
static const AuUInt64 kTlsKeyStaticPointerHandle = AuUInt64(1) << AuUInt64(63 - 1);
|
{
|
||||||
static const AuUInt64 kTlsKeyResettablePointerHandle = AuUInt64(1) << AuUInt64(62 - 1);
|
Primitives::SpinLock lock;
|
||||||
static const AuUInt64 kTlsKeyMask = kTlsKeyResettablePointerHandle | kTlsKeyStaticPointerHandle | kTlsKeyFollowsConvention;
|
void *pContext {};
|
||||||
|
};
|
||||||
class TLSView
|
|
||||||
|
struct AUKN_SYM TLSView
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
using TlsCb = AuFunction<void(void *)>;
|
using TlsCb = AuFunction<void(void *)>;
|
||||||
|
|
||||||
virtual void Remove(AuUInt64 key) = 0;
|
static void Remove(TLSKey &key);
|
||||||
virtual void *GetTLS(AuUInt64 key, AuMach length, bool noAutoCreate = false) = 0;
|
static void *InitTLS(TLSKey &key, AuMach length, const TlsCb &init, const TlsCb &deinit);
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -82,22 +82,25 @@ namespace Aurora::Threading::Threads
|
|||||||
OSThread::OSThread(const ThreadInfo &info) : info_(info)
|
OSThread::OSThread(const ThreadInfo &info) : info_(info)
|
||||||
{
|
{
|
||||||
this->name_ = info.name.value_or("Aurora Thread");
|
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
|
// 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->terminatedSignalLs_ = AuLoop::NewLSEvent(true, false, true);
|
||||||
this->terminateSignalLs_ = AuLoop::NewLSEvent(true, false, true);
|
this->terminateSignalLs_ = AuLoop::NewLSEvent(true, false, true);
|
||||||
|
|
||||||
this->exitOnlyOnce_ = Primitives::CriticalSectionUnique();
|
this->terminated_ = AuThreadPrimitives::EventShared(true, false, true);
|
||||||
SysAssert(this->terminated_ ? true : false, "out of memory");
|
this->terminateSignal_ = AuThreadPrimitives::EventShared(true, false, true);
|
||||||
|
|
||||||
|
SysAssert(this->terminatedSignalLs_ && this->terminateSignalLs_ && this->terminated_ && this->terminateSignal_);
|
||||||
}
|
}
|
||||||
|
|
||||||
OSThread::OSThread() : info_(gDummyThreadInfo)
|
OSThread::OSThread() : info_(gDummyThreadInfo)
|
||||||
{
|
{
|
||||||
this->name_ = "Main Thread";
|
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)
|
OSThread::OSThread(AuUInt64 id) : info_(gDummyThreadInfo)
|
||||||
@ -155,7 +158,7 @@ namespace Aurora::Threading::Threads
|
|||||||
if (this->terminated_)
|
if (this->terminated_)
|
||||||
{
|
{
|
||||||
this->exiting_ = true;
|
this->exiting_ = true;
|
||||||
if (WaitFor(this->terminated_.get(), 5000))
|
if (this->terminated_->LockMS(5'000))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -189,6 +192,7 @@ namespace Aurora::Threading::Threads
|
|||||||
AU_LOCK_GUARD(this->tlsLock_);
|
AU_LOCK_GUARD(this->tlsLock_);
|
||||||
AU_LOCK_GUARD(this->tlsReferenceThread_->tlsLock_);
|
AU_LOCK_GUARD(this->tlsReferenceThread_->tlsLock_);
|
||||||
|
|
||||||
|
SetThreadKey(this->tlsReferenceThread_->tls_);
|
||||||
AuExchange(this->tlsReferenceThread_->tls_, this->tls_);
|
AuExchange(this->tlsReferenceThread_->tls_, this->tls_);
|
||||||
AuExchange(this->tlsReferenceThread_->threadFeatures_, this->threadFeatures_);
|
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
|
// Is is expected for a system thread to release on dtor unlike our aurora threads
|
||||||
void OSThread::HookReleaseThreadResources()
|
void OSThread::HookReleaseThreadResources()
|
||||||
{
|
{
|
||||||
tls_.reset();
|
AU_LOCK_GUARD(this->tlsLock_);
|
||||||
|
|
||||||
for (const auto &feature : this->threadFeatures_)
|
for (const auto &feature : this->threadFeatures_)
|
||||||
{
|
{
|
||||||
feature->Cleanup();
|
feature->Cleanup();
|
||||||
@ -224,7 +227,7 @@ namespace Aurora::Threading::Threads
|
|||||||
|
|
||||||
void OSThread::AddLastHopeTlsHook(const AuSPtr<AuThreads::IThreadFeature> &feature)
|
void OSThread::AddLastHopeTlsHook(const AuSPtr<AuThreads::IThreadFeature> &feature)
|
||||||
{
|
{
|
||||||
// TODO: mutex
|
AU_LOCK_GUARD(this->tlsLock_);
|
||||||
if (!feature)
|
if (!feature)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -443,12 +446,7 @@ namespace Aurora::Threading::Threads
|
|||||||
|
|
||||||
AuSPtr<TLSView> OSThread::GetTlsView()
|
AuSPtr<TLSView> OSThread::GetTlsView()
|
||||||
{
|
{
|
||||||
if (!this->tls_)
|
SysPanic("Deprecated Concept");
|
||||||
{
|
|
||||||
this->tls_ = AuMakeShared<TLSViewImpl>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->tls_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OSThread::ExecuteNewOSContext(AuFunction<void()> task)
|
bool OSThread::ExecuteNewOSContext(AuFunction<void()> task)
|
||||||
@ -468,6 +466,11 @@ namespace Aurora::Threading::Threads
|
|||||||
AuThreading::ContextYield();
|
AuThreading::ContextYield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->tls_)
|
||||||
|
{
|
||||||
|
this->tls_ = GetThreadKey();
|
||||||
|
}
|
||||||
|
|
||||||
this->_ThreadEP();
|
this->_ThreadEP();
|
||||||
}, GetName(), this->info_.stackSize);
|
}, GetName(), this->info_.stackSize);
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ namespace Aurora::Threading::Threads
|
|||||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||||
jmp_buf env;
|
jmp_buf env;
|
||||||
#endif
|
#endif
|
||||||
Primitives::SpinLock tlsLock_;
|
Primitives::Mutex tlsLock_;
|
||||||
AuSPtr<TLSView> tls_;
|
AuUInt32 tls_ {};
|
||||||
OSThread * tlsReferenceThread_ {};
|
OSThread * tlsReferenceThread_ {};
|
||||||
AuString name_;
|
AuString name_;
|
||||||
ThreadInfo info_;
|
ThreadInfo info_;
|
||||||
@ -90,11 +90,11 @@ namespace Aurora::Threading::Threads
|
|||||||
bool contextUsed_{}; // can this thread instance execute code again?
|
bool contextUsed_{}; // can this thread instance execute code again?
|
||||||
Primitives::EventShared_t terminated_;
|
Primitives::EventShared_t terminated_;
|
||||||
Primitives::EventShared_t terminateSignal_;
|
Primitives::EventShared_t terminateSignal_;
|
||||||
AuSPtr<AuLoop::ILSEvent> terminateSignalLs_;
|
AuSPtr<AuLoop::ILSEvent> terminateSignalLs_;
|
||||||
AuSPtr<AuLoop::ILSEvent> terminatedSignalLs_;
|
AuSPtr<AuLoop::ILSEvent> terminatedSignalLs_;
|
||||||
bool bLongJmpOnce {};
|
bool bLongJmpOnce {};
|
||||||
|
|
||||||
Primitives::CriticalSectionUnique_t exitOnlyOnce_;
|
Primitives::CriticalSection exitOnlyOnce_;
|
||||||
|
|
||||||
AuList<AuSPtr<IThreadFeature>> threadFeatures_;
|
AuList<AuSPtr<IThreadFeature>> threadFeatures_;
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ namespace Aurora::Threading::Threads
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEFINE_SPEEDY_TLS(OSFallbackThread, tlsOsFallbackThread);
|
DEFINE_SPEEDY_TLS(OSFallbackThread, tlsOsFallbackThread);
|
||||||
DEFINE_SPEEDY_TLS(IAuroraThread*, tlsCurrentThread);
|
DEFINE_SPEEDY_TLS(IAuroraThread *, tlsCurrentThread);
|
||||||
|
|
||||||
void HandleRemove()
|
void HandleRemove()
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,12 @@ namespace Aurora::Threading::Threads
|
|||||||
{
|
{
|
||||||
AUKN_SYM IAuroraThread *ThreadNew(const ThreadInfo &info)
|
AUKN_SYM IAuroraThread *ThreadNew(const ThreadInfo &info)
|
||||||
{
|
{
|
||||||
if (!info.callbacks) return {};
|
if (!info.callbacks)
|
||||||
|
{
|
||||||
|
SysPushErrorArg();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return _new OSThread(info);
|
return _new OSThread(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,133 +7,153 @@
|
|||||||
***/
|
***/
|
||||||
#include <Source/RuntimeInternal.hpp>
|
#include <Source/RuntimeInternal.hpp>
|
||||||
#include "TLSView.hpp"
|
#include "TLSView.hpp"
|
||||||
|
#include "../Primitives/ThreadCookie.hpp"
|
||||||
|
|
||||||
namespace Aurora::Threading::Threads
|
namespace Aurora::Threading::Threads
|
||||||
{
|
{
|
||||||
void TLSViewImpl::Remove(AuUInt64 key)
|
static AuUInt32 uAtomicCounter {};
|
||||||
|
static thread_local AuUInt32 tlsThreadIndex { };
|
||||||
|
static const auto kMaxMaxLinearThreads = AuNumericLimits<AuUInt16>::max() / 2;
|
||||||
|
|
||||||
|
AuUInt32 GetThreadKey()
|
||||||
{
|
{
|
||||||
AU_LOCK_GUARD(lock_);
|
auto &uKey = tlsThreadIndex;
|
||||||
|
|
||||||
auto a = tls_.find(key);
|
if (!uKey)
|
||||||
if (a == tls_.end())
|
|
||||||
{
|
{
|
||||||
return;
|
uKey = AuAtomicAdd(&uAtomicCounter, 1u);
|
||||||
|
|
||||||
|
if (uKey > kMaxMaxLinearThreads) [[unlikely]]
|
||||||
|
{
|
||||||
|
uKey = uAtomicCounter = kMaxMaxLinearThreads + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &handler = a->second.second;
|
return uKey;
|
||||||
if (handler)
|
|
||||||
{
|
|
||||||
handler(a->second.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
tls_.erase(a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<void*, TlsCb>*value;
|
|
||||||
|
|
||||||
if (!length)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AuTryFind(tls_, key, value))
|
|
||||||
{
|
|
||||||
if (noAutoCreate)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto buf = AuMemory::ZAlloc<void *>(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<void*, TlsCb>*value;
|
|
||||||
|
|
||||||
if (!length)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AuTryFind(tls_, key, value))
|
|
||||||
{
|
|
||||||
return value->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto buf = AuMemory::ZAlloc<void *>(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)
|
void SetThreadKey(AuUInt32 uThreadKey)
|
||||||
{
|
{
|
||||||
init(buf);
|
tlsThreadIndex = uThreadKey;
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<AuSPtr<ViewEntry>> ptrs;
|
||||||
|
AuHashMap<AuUInt, AuSPtr<ViewEntry>> hashMap;
|
||||||
|
|
||||||
|
ViewEntry &GetHandleReference();
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewEntry::~ViewEntry()
|
||||||
|
{
|
||||||
|
if (this->pVoid && this->deinit)
|
||||||
{
|
{
|
||||||
// prevent Add, Remove, Add, Remove stalls
|
this->deinit(this->pVoid);
|
||||||
fence_++;
|
}
|
||||||
if ((fence_ % 10) == 0)
|
}
|
||||||
|
|
||||||
|
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<ViewEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<ViewEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,20 +9,6 @@
|
|||||||
|
|
||||||
namespace Aurora::Threading::Threads
|
namespace Aurora::Threading::Threads
|
||||||
{
|
{
|
||||||
class TLSViewImpl : public TLSView
|
AuUInt32 GetThreadKey();
|
||||||
{
|
void SetThreadKey(AuUInt32 uThreadKey);
|
||||||
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<AuUInt64, AuPair<void*, TlsCb>> tls_;
|
|
||||||
AuUInt64 fence_ = 0;
|
|
||||||
};
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user