VolatileBuffer.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. #ifndef mozalloc_VolatileBuffer_h
  5. #define mozalloc_VolatileBuffer_h
  6. #include "mozilla/mozalloc.h"
  7. #include "mozilla/Mutex.h"
  8. #include "mozilla/RefPtr.h"
  9. #include "mozilla/MemoryReporting.h"
  10. #include "mozilla/RefCounted.h"
  11. /* VolatileBuffer
  12. *
  13. * This class represents a piece of memory that can potentially be reclaimed
  14. * by the OS when not in use. As long as there are one or more
  15. * VolatileBufferPtrs holding on to a VolatileBuffer, the memory will remain
  16. * available. However, when there are no VolatileBufferPtrs holding a
  17. * VolatileBuffer, the OS can purge the pages if it wants to. The OS can make
  18. * better decisions about what pages to purge than we can.
  19. *
  20. * VolatileBuffers may not always be volatile - if the allocation is too small,
  21. * or if the OS doesn't support the feature, or if the OS doesn't want to,
  22. * the buffer will be allocated on heap.
  23. *
  24. * VolatileBuffer allocations are fallible. They are intended for uses where
  25. * one may allocate large buffers for caching data. Init() must be called
  26. * exactly once.
  27. *
  28. * After getting a reference to VolatileBuffer using VolatileBufferPtr,
  29. * WasPurged() can be used to check if the OS purged any pages in the buffer.
  30. * The OS cannot purge a buffer immediately after a VolatileBuffer is
  31. * initialized. At least one VolatileBufferPtr must be created before the
  32. * buffer can be purged, so the first use of VolatileBufferPtr does not need
  33. * to check WasPurged().
  34. *
  35. * When a buffer is purged, some or all of the buffer is zeroed out. This
  36. * API cannot tell which parts of the buffer were lost.
  37. *
  38. * VolatileBuffer and VolatileBufferPtr are threadsafe.
  39. */
  40. namespace mozilla {
  41. class VolatileBuffer
  42. {
  43. friend class VolatileBufferPtr_base;
  44. public:
  45. MOZ_DECLARE_REFCOUNTED_TYPENAME(VolatileBuffer)
  46. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VolatileBuffer)
  47. VolatileBuffer();
  48. /* aAlignment must be a multiple of the pointer size */
  49. bool Init(size_t aSize, size_t aAlignment = sizeof(void*));
  50. size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
  51. size_t NonHeapSizeOfExcludingThis() const;
  52. bool OnHeap() const;
  53. protected:
  54. bool Lock(void** aBuf);
  55. void Unlock();
  56. private:
  57. ~VolatileBuffer();
  58. /**
  59. * Protects mLockCount, mFirstLock, and changes to the volatility of our
  60. * buffer. Other member variables are read-only except in Init() and the
  61. * destructor.
  62. */
  63. Mutex mMutex;
  64. void* mBuf;
  65. size_t mSize;
  66. int mLockCount;
  67. #if defined(XP_WIN)
  68. bool mHeap;
  69. bool mFirstLock;
  70. #endif
  71. };
  72. class VolatileBufferPtr_base {
  73. public:
  74. explicit VolatileBufferPtr_base(VolatileBuffer* vbuf)
  75. : mVBuf(vbuf)
  76. , mMapping(nullptr)
  77. , mPurged(false)
  78. {
  79. Lock();
  80. }
  81. ~VolatileBufferPtr_base() {
  82. Unlock();
  83. }
  84. bool WasBufferPurged() const {
  85. return mPurged;
  86. }
  87. protected:
  88. RefPtr<VolatileBuffer> mVBuf;
  89. void* mMapping;
  90. void Set(VolatileBuffer* vbuf) {
  91. Unlock();
  92. mVBuf = vbuf;
  93. Lock();
  94. }
  95. private:
  96. bool mPurged;
  97. void Lock() {
  98. if (mVBuf) {
  99. mPurged = !mVBuf->Lock(&mMapping);
  100. } else {
  101. mMapping = nullptr;
  102. mPurged = false;
  103. }
  104. }
  105. void Unlock() {
  106. if (mVBuf) {
  107. mVBuf->Unlock();
  108. }
  109. }
  110. };
  111. template <class T>
  112. class VolatileBufferPtr : public VolatileBufferPtr_base
  113. {
  114. public:
  115. explicit VolatileBufferPtr(VolatileBuffer* vbuf) : VolatileBufferPtr_base(vbuf) {}
  116. VolatileBufferPtr() : VolatileBufferPtr_base(nullptr) {}
  117. VolatileBufferPtr(VolatileBufferPtr&& aOther)
  118. : VolatileBufferPtr_base(aOther.mVBuf)
  119. {
  120. aOther.Set(nullptr);
  121. }
  122. operator T*() const {
  123. return (T*) mMapping;
  124. }
  125. VolatileBufferPtr& operator=(VolatileBuffer* aVBuf)
  126. {
  127. Set(aVBuf);
  128. return *this;
  129. }
  130. VolatileBufferPtr& operator=(VolatileBufferPtr&& aOther)
  131. {
  132. MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
  133. Set(aOther.mVBuf);
  134. aOther.Set(nullptr);
  135. return *this;
  136. }
  137. private:
  138. VolatileBufferPtr(VolatileBufferPtr const& vbufptr) = delete;
  139. };
  140. } // namespace mozilla
  141. #endif /* mozalloc_VolatileBuffer_h */