/////////////////////////////////////////////////////////////////////////////// // // // 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" #include #include "dxc/Support/WinIncludes.h" #include static DWORD g_ThreadMallocTlsIndex; static IMalloc *g_pDefaultMalloc; // Used by DllMain to set up and tear down per-thread tracking. HRESULT DxcInitThreadMalloc() throw(); void DxcCleanupThreadMalloc() throw(); // Used by APIs that are entry points to set up per-thread/invocation allocator. void DxcSetThreadMalloc(IMalloc *pMalloc) throw(); void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw(); void DxcClearThreadMalloc() throw(); // Used to retrieve the current invocation's allocator or perform an alloc/free/realloc. IMalloc *DxcGetThreadMallocNoRef() throw(); _Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw(); void DxcThreadFree(void *) throw(); HRESULT DxcInitThreadMalloc() { 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_pDefaultMalloc->Release(); g_pDefaultMalloc = nullptr; return E_OUTOFMEMORY; } return S_OK; } void DxcCleanupThreadMalloc() { if (g_ThreadMallocTlsIndex) { TlsFree(g_ThreadMallocTlsIndex); g_ThreadMallocTlsIndex = 0; DXASSERT(g_pDefaultMalloc, "else DxcInitThreadMalloc didn't work/fail atomically"); g_pDefaultMalloc->Release(); g_pDefaultMalloc = nullptr; } } IMalloc *DxcGetThreadMallocNoRef() { DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); return reinterpret_cast(TlsGetValue(g_ThreadMallocTlsIndex)); } void DxcClearThreadMalloc() { DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); IMalloc *pMalloc = DxcGetThreadMallocNoRef(); DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, nullptr)); pMalloc->Release(); } void DxcSetThreadMalloc(IMalloc *pMalloc) { DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); DXASSERT(DxcGetThreadMallocNoRef() == nullptr, "else nested allocation invoked"); DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc)); pMalloc->AddRef(); } void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) { DxcSetThreadMalloc(pMalloc ? pMalloc : g_pDefaultMalloc); } IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) { DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc"); IMalloc *pPrior = DxcGetThreadMallocNoRef(); if (ppPrior) { *ppPrior = pPrior; } DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc)); return pMalloc; } IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) { return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior); }