[linux-port] Use cross-platform TLS methods (#1338)
LLVM includes cross-platform thread local storage methods for saving, retrieving, and deleting thread-specific objects. Using these methods is superior to the thread_local storage qualifier because the former works on Apple, Linux, and Windows. It also uses the same mechanism as the previous Windows implementation used without compiler idiosyncracies. Placement new is needed in DxcInitThreadMalloc because operator new requires the TLS malloc to be in place.
This commit is contained in:
Родитель
a88cc5d133
Коммит
0ba5e55bf3
|
@ -13,9 +13,10 @@
|
|||
#include <specstrings.h>
|
||||
|
||||
#include "dxc/Support/WinIncludes.h"
|
||||
#include "llvm/Support/ThreadLocal.h"
|
||||
#include <memory>
|
||||
|
||||
static DWORD g_ThreadMallocTlsIndex;
|
||||
static llvm::sys::ThreadLocal<IMalloc> *g_ThreadMallocTls;
|
||||
static IMalloc *g_pDefaultMalloc;
|
||||
|
||||
// Used by DllMain to set up and tear down per-thread tracking.
|
||||
|
@ -33,28 +34,28 @@ _Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nB
|
|||
void DxcThreadFree(void *) throw();
|
||||
|
||||
HRESULT DxcInitThreadMalloc() throw() {
|
||||
DXASSERT(g_ThreadMallocTlsIndex == 0, "else InitThreadMalloc already called");
|
||||
DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called");
|
||||
|
||||
// We capture the default malloc early to avoid potential failures later on.
|
||||
HRESULT hrMalloc = CoGetMalloc(1, &g_pDefaultMalloc);
|
||||
if (FAILED(hrMalloc)) return hrMalloc;
|
||||
|
||||
g_ThreadMallocTlsIndex = TlsAlloc();
|
||||
if (g_ThreadMallocTlsIndex == TLS_OUT_OF_INDEXES) {
|
||||
g_ThreadMallocTlsIndex = 0;
|
||||
g_ThreadMallocTls = (llvm::sys::ThreadLocal<IMalloc>*)g_pDefaultMalloc->Alloc(sizeof(llvm::sys::ThreadLocal<IMalloc>));
|
||||
if (g_ThreadMallocTls == nullptr) {
|
||||
g_pDefaultMalloc->Release();
|
||||
g_pDefaultMalloc = nullptr;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
g_ThreadMallocTls = new(g_ThreadMallocTls) llvm::sys::ThreadLocal<IMalloc>;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void DxcCleanupThreadMalloc() throw() {
|
||||
if (g_ThreadMallocTlsIndex) {
|
||||
TlsFree(g_ThreadMallocTlsIndex);
|
||||
g_ThreadMallocTlsIndex = 0;
|
||||
if (g_ThreadMallocTls) {
|
||||
g_ThreadMallocTls->llvm::sys::ThreadLocal<IMalloc>::~ThreadLocal();
|
||||
g_pDefaultMalloc->Free(g_ThreadMallocTls);
|
||||
g_ThreadMallocTls = nullptr;
|
||||
DXASSERT(g_pDefaultMalloc, "else DxcInitThreadMalloc didn't work/fail atomically");
|
||||
g_pDefaultMalloc->Release();
|
||||
g_pDefaultMalloc = nullptr;
|
||||
|
@ -62,31 +63,32 @@ void DxcCleanupThreadMalloc() throw() {
|
|||
}
|
||||
|
||||
IMalloc *DxcGetThreadMallocNoRef() throw() {
|
||||
DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
return reinterpret_cast<IMalloc *>(TlsGetValue(g_ThreadMallocTlsIndex));
|
||||
DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
return g_ThreadMallocTls->get();
|
||||
}
|
||||
|
||||
void DxcClearThreadMalloc() throw() {
|
||||
DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
IMalloc *pMalloc = DxcGetThreadMallocNoRef();
|
||||
DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, nullptr));
|
||||
g_ThreadMallocTls->erase();
|
||||
pMalloc->Release();
|
||||
}
|
||||
void DxcSetThreadMalloc(IMalloc *pMalloc) throw() {
|
||||
DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
DXASSERT(DxcGetThreadMallocNoRef() == nullptr, "else nested allocation invoked");
|
||||
DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc));
|
||||
g_ThreadMallocTls->set(pMalloc);
|
||||
pMalloc->AddRef();
|
||||
}
|
||||
void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw() {
|
||||
DxcSetThreadMalloc(pMalloc ? pMalloc : g_pDefaultMalloc);
|
||||
}
|
||||
IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) throw() {
|
||||
DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
|
||||
IMalloc *pPrior = DxcGetThreadMallocNoRef();
|
||||
if (ppPrior) {
|
||||
*ppPrior = pPrior;
|
||||
}
|
||||
DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc));
|
||||
g_ThreadMallocTls->set(pMalloc);
|
||||
return pMalloc;
|
||||
}
|
||||
IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) throw() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче