AllocationPolicyManager.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. //
  6. // AllocationPolicyManager allows a caller/host to disallow new page allocations
  7. // and to track current page usage.
  8. //
  9. // NOTE: For now, we are only tracking reserved page count.
  10. // Consider whether we should also (or maybe only) track committed page count.
  11. class AllocationPolicyManager
  12. {
  13. public:
  14. enum MemoryAllocateEvent
  15. {
  16. MemoryAllocate = 0,
  17. MemoryFree = 1,
  18. MemoryFailure = 2,
  19. MemoryMax = 2,
  20. };
  21. typedef bool (__stdcall * PageAllocatorMemoryAllocationCallback)(__in LPVOID context,
  22. __in AllocationPolicyManager::MemoryAllocateEvent allocationEvent,
  23. __in size_t allocationSize);
  24. private:
  25. size_t memoryLimit;
  26. size_t currentMemory;
  27. bool supportConcurrency;
  28. CriticalSection cs;
  29. void * context;
  30. PageAllocatorMemoryAllocationCallback memoryAllocationCallback;
  31. public:
  32. AllocationPolicyManager(bool needConcurrencySupport) :
  33. memoryLimit((size_t)-1),
  34. currentMemory(0),
  35. supportConcurrency(needConcurrencySupport),
  36. context(NULL),
  37. memoryAllocationCallback(NULL)
  38. {
  39. }
  40. ~AllocationPolicyManager()
  41. {
  42. Assert(currentMemory == 0);
  43. }
  44. size_t GetUsage()
  45. {
  46. return currentMemory;
  47. }
  48. size_t GetLimit()
  49. {
  50. return memoryLimit;
  51. }
  52. void SetLimit(size_t newLimit)
  53. {
  54. memoryLimit = newLimit;
  55. }
  56. bool RequestAlloc(DECLSPEC_GUARD_OVERFLOW size_t byteCount, bool externalAlloc = false)
  57. {
  58. if (supportConcurrency)
  59. {
  60. AutoCriticalSection auto_cs(&cs);
  61. return RequestAllocImpl(byteCount, externalAlloc);
  62. }
  63. else
  64. {
  65. return RequestAllocImpl(byteCount, externalAlloc);
  66. }
  67. }
  68. void ReportFailure(size_t byteCount)
  69. {
  70. if (supportConcurrency)
  71. {
  72. AutoCriticalSection auto_cs(&cs);
  73. ReportFreeImpl(MemoryAllocateEvent::MemoryFailure, byteCount);
  74. }
  75. else
  76. {
  77. ReportFreeImpl(MemoryAllocateEvent::MemoryFailure, byteCount);
  78. }
  79. }
  80. void ReportFree(size_t byteCount)
  81. {
  82. if (supportConcurrency)
  83. {
  84. AutoCriticalSection auto_cs(&cs);
  85. ReportFreeImpl(MemoryAllocateEvent::MemoryFree, byteCount);
  86. }
  87. else
  88. {
  89. ReportFreeImpl(MemoryAllocateEvent::MemoryFree, byteCount);
  90. }
  91. }
  92. void SetMemoryAllocationCallback(LPVOID newContext, PageAllocatorMemoryAllocationCallback callback)
  93. {
  94. this->memoryAllocationCallback = callback;
  95. if (callback == NULL)
  96. {
  97. // doesn't make sense to have non-null context when the callback is NULL.
  98. this->context = NULL;
  99. }
  100. else
  101. {
  102. this->context = newContext;
  103. }
  104. }
  105. private:
  106. inline bool RequestAllocImpl(size_t byteCount, bool externalAlloc = false)
  107. {
  108. size_t newCurrentMemory = currentMemory + byteCount;
  109. if (newCurrentMemory < currentMemory ||
  110. newCurrentMemory > memoryLimit ||
  111. (memoryAllocationCallback != NULL && !memoryAllocationCallback(context, MemoryAllocateEvent::MemoryAllocate, byteCount)))
  112. {
  113. if (memoryAllocationCallback != NULL)
  114. {
  115. memoryAllocationCallback(context, MemoryAllocateEvent::MemoryFailure, byteCount);
  116. }
  117. // oopjit number allocator allocated pages, we can't stop it from allocating so just increase the usage number
  118. if (externalAlloc)
  119. {
  120. currentMemory = newCurrentMemory;
  121. }
  122. return false;
  123. }
  124. else
  125. {
  126. currentMemory = newCurrentMemory;
  127. return true;
  128. }
  129. }
  130. inline void ReportFreeImpl(MemoryAllocateEvent allocationEvent, size_t byteCount)
  131. {
  132. Assert(currentMemory >= byteCount);
  133. currentMemory = currentMemory - byteCount;
  134. if (memoryAllocationCallback != NULL)
  135. {
  136. // The callback should be minimal, with no possibility of calling back to us.
  137. // Note that this can be called both in script or out of script.
  138. memoryAllocationCallback(context, allocationEvent, byteCount);
  139. }
  140. }
  141. };