VolatileBufferWindows.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "VolatileBuffer.h"
  5. #include "mozilla/Assertions.h"
  6. #include "mozilla/mozalloc.h"
  7. #include "mozilla/WindowsVersion.h"
  8. #include <windows.h>
  9. #ifdef MOZ_MEMORY
  10. extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
  11. #endif
  12. #ifndef MEM_RESET_UNDO
  13. #define MEM_RESET_UNDO 0x1000000
  14. #endif
  15. #define MIN_VOLATILE_ALLOC_SIZE 8192
  16. namespace mozilla {
  17. VolatileBuffer::VolatileBuffer()
  18. : mMutex("VolatileBuffer")
  19. , mBuf(nullptr)
  20. , mSize(0)
  21. , mLockCount(0)
  22. , mHeap(false)
  23. , mFirstLock(true)
  24. {
  25. }
  26. bool
  27. VolatileBuffer::Init(size_t aSize, size_t aAlignment)
  28. {
  29. MOZ_ASSERT(!mSize && !mBuf, "Init called twice");
  30. MOZ_ASSERT(!(aAlignment % sizeof(void *)),
  31. "Alignment must be multiple of pointer size");
  32. mSize = aSize;
  33. if (aSize < MIN_VOLATILE_ALLOC_SIZE) {
  34. goto heap_alloc;
  35. }
  36. static bool sUndoSupported = IsWin8OrLater();
  37. if (!sUndoSupported) {
  38. goto heap_alloc;
  39. }
  40. mBuf = VirtualAllocEx(GetCurrentProcess(),
  41. nullptr,
  42. mSize,
  43. MEM_COMMIT | MEM_RESERVE,
  44. PAGE_READWRITE);
  45. if (mBuf) {
  46. return true;
  47. }
  48. heap_alloc:
  49. #ifdef MOZ_MEMORY
  50. posix_memalign(&mBuf, aAlignment, aSize);
  51. #else
  52. mBuf = _aligned_malloc(aSize, aAlignment);
  53. #endif
  54. mHeap = true;
  55. return !!mBuf;
  56. }
  57. VolatileBuffer::~VolatileBuffer()
  58. {
  59. MOZ_ASSERT(mLockCount == 0, "Being destroyed with non-zero lock count?");
  60. if (OnHeap()) {
  61. #ifdef MOZ_MEMORY
  62. free(mBuf);
  63. #else
  64. _aligned_free(mBuf);
  65. #endif
  66. } else {
  67. VirtualFreeEx(GetCurrentProcess(), mBuf, 0, MEM_RELEASE);
  68. }
  69. }
  70. bool
  71. VolatileBuffer::Lock(void** aBuf)
  72. {
  73. MutexAutoLock lock(mMutex);
  74. MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer");
  75. *aBuf = mBuf;
  76. if (++mLockCount > 1 || OnHeap()) {
  77. return true;
  78. }
  79. // MEM_RESET_UNDO's behavior is undefined when called on memory that
  80. // hasn't been MEM_RESET.
  81. if (mFirstLock) {
  82. mFirstLock = false;
  83. return true;
  84. }
  85. void* addr = VirtualAllocEx(GetCurrentProcess(),
  86. mBuf,
  87. mSize,
  88. MEM_RESET_UNDO,
  89. PAGE_READWRITE);
  90. return !!addr;
  91. }
  92. void
  93. VolatileBuffer::Unlock()
  94. {
  95. MutexAutoLock lock(mMutex);
  96. MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!");
  97. if (--mLockCount || OnHeap()) {
  98. return;
  99. }
  100. void* addr = VirtualAllocEx(GetCurrentProcess(),
  101. mBuf,
  102. mSize,
  103. MEM_RESET,
  104. PAGE_READWRITE);
  105. MOZ_ASSERT(addr, "Failed to MEM_RESET");
  106. }
  107. bool
  108. VolatileBuffer::OnHeap() const
  109. {
  110. return mHeap;
  111. }
  112. size_t
  113. VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  114. {
  115. if (OnHeap()) {
  116. #ifdef MOZ_MEMORY
  117. return aMallocSizeOf(mBuf);
  118. #else
  119. return mSize;
  120. #endif
  121. }
  122. return 0;
  123. }
  124. size_t
  125. VolatileBuffer::NonHeapSizeOfExcludingThis() const
  126. {
  127. if (OnHeap()) {
  128. return 0;
  129. }
  130. return (mSize + 4095) & ~4095;
  131. }
  132. } // namespace mozilla