/////////////////////////////////////////////////////////////////////////////// // // // dxcmem.cpp // // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is distributed under the University of Illinois Open Source // // License. See LICENSE.TXT for details. // // // // Provides support for a thread-local allocator. // // // /////////////////////////////////////////////////////////////////////////////// #include "dxc/Support/Global.h" #ifdef _WIN32 #include #endif #include "dxc/Support/WinIncludes.h" #include "dxc/Support/WinFunctions.h" #include "llvm/Support/ThreadLocal.h" #include static llvm::sys::ThreadLocal *g_ThreadMallocTls; static IMalloc *g_pDefaultMalloc; #ifndef _WIN32 #pragma GCC visibility push(hidden) #endif HRESULT DxcInitThreadMalloc() throw() { 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_ThreadMallocTls = (llvm::sys::ThreadLocal*)g_pDefaultMalloc->Alloc(sizeof(llvm::sys::ThreadLocal)); if (g_ThreadMallocTls == nullptr) { g_pDefaultMalloc->Release(); g_pDefaultMalloc = nullptr; return E_OUTOFMEMORY; } g_ThreadMallocTls = new(g_ThreadMallocTls) llvm::sys::ThreadLocal; return S_OK; } void DxcCleanupThreadMalloc() throw() { if (g_ThreadMallocTls) { g_ThreadMallocTls->llvm::sys::ThreadLocal::~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; } } IMalloc *DxcGetThreadMallocNoRef() throw() { DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); return g_ThreadMallocTls->get(); } void DxcClearThreadMalloc() throw() { DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); IMalloc *pMalloc = DxcGetThreadMallocNoRef(); g_ThreadMallocTls->erase(); pMalloc->Release(); } void DxcSetThreadMalloc(IMalloc *pMalloc) throw() { DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); DXASSERT(DxcGetThreadMallocNoRef() == nullptr, "else nested allocation invoked"); 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_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); IMalloc *pPrior = DxcGetThreadMallocNoRef(); if (ppPrior) { *ppPrior = pPrior; } g_ThreadMallocTls->set(pMalloc); return pMalloc; } IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) throw() { return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior); } #ifndef _WIN32 #pragma GCC visibility pop #endif