dxcmem.cpp 3.3 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. HRESULT DxcInitThreadMalloc() throw() {
  22. DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called");
  23. // We capture the default malloc early to avoid potential failures later on.
  24. HRESULT hrMalloc = CoGetMalloc(1, &g_pDefaultMalloc);
  25. if (FAILED(hrMalloc)) return hrMalloc;
  26. g_ThreadMallocTls = (llvm::sys::ThreadLocal<IMalloc>*)g_pDefaultMalloc->Alloc(sizeof(llvm::sys::ThreadLocal<IMalloc>));
  27. if (g_ThreadMallocTls == nullptr) {
  28. g_pDefaultMalloc->Release();
  29. g_pDefaultMalloc = nullptr;
  30. return E_OUTOFMEMORY;
  31. }
  32. g_ThreadMallocTls = new(g_ThreadMallocTls) llvm::sys::ThreadLocal<IMalloc>;
  33. return S_OK;
  34. }
  35. void DxcCleanupThreadMalloc() throw() {
  36. if (g_ThreadMallocTls) {
  37. DXASSERT(g_pDefaultMalloc, "else DxcInitThreadMalloc didn't work/fail atomically");
  38. g_ThreadMallocTls->llvm::sys::ThreadLocal<IMalloc>::~ThreadLocal();
  39. g_pDefaultMalloc->Free(g_ThreadMallocTls);
  40. g_ThreadMallocTls = nullptr;
  41. }
  42. }
  43. IMalloc *DxcGetThreadMallocNoRef() throw() {
  44. if (g_ThreadMallocTls == nullptr) {
  45. return g_pDefaultMalloc;
  46. }
  47. return g_ThreadMallocTls->get();
  48. }
  49. void DxcClearThreadMalloc() throw() {
  50. if (g_ThreadMallocTls != nullptr) {
  51. IMalloc *pMalloc = DxcGetThreadMallocNoRef();
  52. g_ThreadMallocTls->erase();
  53. if (pMalloc != nullptr) {
  54. pMalloc->Release();
  55. }
  56. }
  57. }
  58. void DxcSetThreadMallocToDefault() 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(g_pDefaultMalloc);
  62. g_pDefaultMalloc->AddRef();
  63. }
  64. static IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) throw() {
  65. DXASSERT(g_ThreadMallocTls != nullptr, "else prior to DxcInitThreadMalloc or after DxcCleanupThreadMalloc");
  66. IMalloc *pPrior = DxcGetThreadMallocNoRef();
  67. if (ppPrior) {
  68. *ppPrior = pPrior;
  69. }
  70. g_ThreadMallocTls->set(pMalloc);
  71. return pMalloc;
  72. }
  73. DxcThreadMalloc::DxcThreadMalloc(IMalloc *pMallocOrNull) throw() {
  74. p = DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, &pPrior);
  75. }
  76. DxcThreadMalloc::~DxcThreadMalloc() {
  77. DxcSwapThreadMalloc(pPrior, nullptr);
  78. }