dxcmem.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. #ifdef _WIN32
  13. #include <specstrings.h>
  14. #endif
  15. #include "dxc/Support/WinIncludes.h"
  16. #include "dxc/Support/WinFunctions.h"
  17. #include "llvm/Support/ThreadLocal.h"
  18. #include <memory>
  19. static llvm::sys::ThreadLocal<IMalloc> *g_ThreadMallocTls;
  20. static IMalloc *g_pDefaultMalloc;
  21. #ifndef _WIN32
  22. #pragma GCC visibility push(hidden)
  23. #endif
  24. HRESULT DxcInitThreadMalloc() throw() {
  25. DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called");
  26. // We capture the default malloc early to avoid potential failures later on.
  27. HRESULT hrMalloc = CoGetMalloc(1, &g_pDefaultMalloc);
  28. if (FAILED(hrMalloc)) return hrMalloc;
  29. g_ThreadMallocTls = (llvm::sys::ThreadLocal<IMalloc>*)g_pDefaultMalloc->Alloc(sizeof(llvm::sys::ThreadLocal<IMalloc>));
  30. if (g_ThreadMallocTls == nullptr) {
  31. g_pDefaultMalloc->Release();
  32. g_pDefaultMalloc = nullptr;
  33. return E_OUTOFMEMORY;
  34. }
  35. g_ThreadMallocTls = new(g_ThreadMallocTls) llvm::sys::ThreadLocal<IMalloc>;
  36. return S_OK;
  37. }
  38. void DxcCleanupThreadMalloc() throw() {
  39. if (g_ThreadMallocTls) {
  40. g_ThreadMallocTls->llvm::sys::ThreadLocal<IMalloc>::~ThreadLocal();
  41. g_pDefaultMalloc->Free(g_ThreadMallocTls);
  42. g_ThreadMallocTls = nullptr;
  43. DXASSERT(g_pDefaultMalloc, "else DxcInitThreadMalloc didn't work/fail atomically");
  44. g_pDefaultMalloc->Release();
  45. g_pDefaultMalloc = nullptr;
  46. }
  47. }
  48. IMalloc *DxcGetThreadMallocNoRef() throw() {
  49. DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  50. return g_ThreadMallocTls->get();
  51. }
  52. void DxcClearThreadMalloc() throw() {
  53. DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  54. IMalloc *pMalloc = DxcGetThreadMallocNoRef();
  55. g_ThreadMallocTls->erase();
  56. pMalloc->Release();
  57. }
  58. void DxcSetThreadMalloc(IMalloc *pMalloc) throw() {
  59. DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  60. DXASSERT(DxcGetThreadMallocNoRef() == nullptr, "else nested allocation invoked");
  61. g_ThreadMallocTls->set(pMalloc);
  62. pMalloc->AddRef();
  63. }
  64. void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw() {
  65. DxcSetThreadMalloc(pMalloc ? pMalloc : g_pDefaultMalloc);
  66. }
  67. IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) throw() {
  68. DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  69. IMalloc *pPrior = DxcGetThreadMallocNoRef();
  70. if (ppPrior) {
  71. *ppPrior = pPrior;
  72. }
  73. g_ThreadMallocTls->set(pMalloc);
  74. return pMalloc;
  75. }
  76. IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) throw() {
  77. return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior);
  78. }
  79. #ifndef _WIN32
  80. #pragma GCC visibility pop
  81. #endif