dxcmem.cpp 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // dxcmem.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides support for a thread-local allocator. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/Support/Global.h"
  12. #include <specstrings.h>
  13. #include "dxc/Support/WinIncludes.h"
  14. #include <memory>
  15. static DWORD g_ThreadMallocTlsIndex;
  16. static IMalloc *g_pDefaultMalloc;
  17. // Used by DllMain to set up and tear down per-thread tracking.
  18. HRESULT DxcInitThreadMalloc() throw();
  19. void DxcCleanupThreadMalloc() throw();
  20. // Used by APIs that are entry points to set up per-thread/invocation allocator.
  21. void DxcSetThreadMalloc(IMalloc *pMalloc) throw();
  22. void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw();
  23. void DxcClearThreadMalloc() throw();
  24. // Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
  25. IMalloc *DxcGetThreadMallocNoRef() throw();
  26. _Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw();
  27. void DxcThreadFree(void *) throw();
  28. HRESULT DxcInitThreadMalloc() {
  29. DXASSERT(g_ThreadMallocTlsIndex == 0, "else InitThreadMalloc already called");
  30. DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called");
  31. // We capture the default malloc early to avoid potential failures later on.
  32. HRESULT hrMalloc = CoGetMalloc(1, &g_pDefaultMalloc);
  33. if (FAILED(hrMalloc)) return hrMalloc;
  34. g_ThreadMallocTlsIndex = TlsAlloc();
  35. if (g_ThreadMallocTlsIndex == TLS_OUT_OF_INDEXES) {
  36. g_ThreadMallocTlsIndex = 0;
  37. g_pDefaultMalloc->Release();
  38. g_pDefaultMalloc = nullptr;
  39. return E_OUTOFMEMORY;
  40. }
  41. return S_OK;
  42. }
  43. void DxcCleanupThreadMalloc() {
  44. if (g_ThreadMallocTlsIndex) {
  45. TlsFree(g_ThreadMallocTlsIndex);
  46. g_ThreadMallocTlsIndex = 0;
  47. DXASSERT(g_pDefaultMalloc, "else DxcInitThreadMalloc didn't work/fail atomically");
  48. g_pDefaultMalloc->Release();
  49. g_pDefaultMalloc = nullptr;
  50. }
  51. }
  52. IMalloc *DxcGetThreadMallocNoRef() {
  53. DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  54. return reinterpret_cast<IMalloc *>(TlsGetValue(g_ThreadMallocTlsIndex));
  55. }
  56. void DxcClearThreadMalloc() {
  57. DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  58. IMalloc *pMalloc = DxcGetThreadMallocNoRef();
  59. DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, nullptr));
  60. pMalloc->Release();
  61. }
  62. void DxcSetThreadMalloc(IMalloc *pMalloc) {
  63. DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  64. DXASSERT(DxcGetThreadMallocNoRef() == nullptr, "else nested allocation invoked");
  65. DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc));
  66. pMalloc->AddRef();
  67. }
  68. void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) {
  69. DxcSetThreadMalloc(pMalloc ? pMalloc : g_pDefaultMalloc);
  70. }
  71. IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) {
  72. DXASSERT(g_ThreadMallocTlsIndex != 0, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  73. IMalloc *pPrior = DxcGetThreadMallocNoRef();
  74. if (ppPrior) {
  75. *ppPrior = pPrior;
  76. }
  77. DXVERIFY_NOMSG(TlsSetValue(g_ThreadMallocTlsIndex, pMalloc));
  78. return pMalloc;
  79. }
  80. IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) {
  81. return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior);
  82. }