summaryrefslogtreecommitdiffstats
path: root/memory/volatile/VolatileBuffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'memory/volatile/VolatileBuffer.h')
-rw-r--r--memory/volatile/VolatileBuffer.h161
1 files changed, 161 insertions, 0 deletions
diff --git a/memory/volatile/VolatileBuffer.h b/memory/volatile/VolatileBuffer.h
new file mode 100644
index 0000000000..badd7f3cec
--- /dev/null
+++ b/memory/volatile/VolatileBuffer.h
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozalloc_VolatileBuffer_h
+#define mozalloc_VolatileBuffer_h
+
+#include "mozilla/mozalloc.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/RefCounted.h"
+
+/* VolatileBuffer
+ *
+ * This class represents a piece of memory that can potentially be reclaimed
+ * by the OS when not in use. As long as there are one or more
+ * VolatileBufferPtrs holding on to a VolatileBuffer, the memory will remain
+ * available. However, when there are no VolatileBufferPtrs holding a
+ * VolatileBuffer, the OS can purge the pages if it wants to. The OS can make
+ * better decisions about what pages to purge than we can.
+ *
+ * VolatileBuffers may not always be volatile - if the allocation is too small,
+ * or if the OS doesn't support the feature, or if the OS doesn't want to,
+ * the buffer will be allocated on heap.
+ *
+ * VolatileBuffer allocations are fallible. They are intended for uses where
+ * one may allocate large buffers for caching data. Init() must be called
+ * exactly once.
+ *
+ * After getting a reference to VolatileBuffer using VolatileBufferPtr,
+ * WasPurged() can be used to check if the OS purged any pages in the buffer.
+ * The OS cannot purge a buffer immediately after a VolatileBuffer is
+ * initialized. At least one VolatileBufferPtr must be created before the
+ * buffer can be purged, so the first use of VolatileBufferPtr does not need
+ * to check WasPurged().
+ *
+ * When a buffer is purged, some or all of the buffer is zeroed out. This
+ * API cannot tell which parts of the buffer were lost.
+ *
+ * VolatileBuffer and VolatileBufferPtr are threadsafe.
+ */
+
+namespace mozilla {
+
+class VolatileBuffer {
+ friend class VolatileBufferPtr_base;
+
+ public:
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(VolatileBuffer)
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VolatileBuffer)
+
+ VolatileBuffer();
+
+ /* aAlignment must be a multiple of the pointer size */
+ bool Init(size_t aSize, size_t aAlignment = sizeof(void*));
+
+ size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
+ size_t NonHeapSizeOfExcludingThis() const;
+ bool OnHeap() const;
+
+ protected:
+ bool Lock(void** aBuf);
+ void Unlock();
+
+ private:
+ ~VolatileBuffer();
+
+ /**
+ * Protects mLockCount, mFirstLock, and changes to the volatility of our
+ * buffer. Other member variables are read-only except in Init() and the
+ * destructor.
+ */
+ Mutex mMutex MOZ_UNANNOTATED;
+
+ void* mBuf;
+ size_t mSize;
+ int mLockCount;
+#if defined(ANDROID)
+ int mFd;
+#elif defined(XP_DARWIN)
+ bool mHeap;
+#elif defined(XP_WIN)
+ bool mHeap;
+ bool mFirstLock;
+#endif
+};
+
+class VolatileBufferPtr_base {
+ public:
+ explicit VolatileBufferPtr_base(VolatileBuffer* vbuf)
+ : mVBuf(vbuf), mMapping(nullptr), mPurged(false) {
+ Lock();
+ }
+
+ ~VolatileBufferPtr_base() { Unlock(); }
+
+ bool WasBufferPurged() const { return mPurged; }
+
+ protected:
+ RefPtr<VolatileBuffer> mVBuf;
+ void* mMapping;
+
+ void Set(VolatileBuffer* vbuf) {
+ Unlock();
+ mVBuf = vbuf;
+ Lock();
+ }
+
+ private:
+ bool mPurged;
+
+ void Lock() {
+ if (mVBuf) {
+ mPurged = !mVBuf->Lock(&mMapping);
+ } else {
+ mMapping = nullptr;
+ mPurged = false;
+ }
+ }
+
+ void Unlock() {
+ if (mVBuf) {
+ mVBuf->Unlock();
+ }
+ }
+};
+
+template <class T>
+class VolatileBufferPtr : public VolatileBufferPtr_base {
+ public:
+ explicit VolatileBufferPtr(VolatileBuffer* vbuf)
+ : VolatileBufferPtr_base(vbuf) {}
+ VolatileBufferPtr() : VolatileBufferPtr_base(nullptr) {}
+
+ VolatileBufferPtr(VolatileBufferPtr&& aOther)
+ : VolatileBufferPtr_base(aOther.mVBuf) {
+ aOther.Set(nullptr);
+ }
+
+ operator T*() const { return (T*)mMapping; }
+
+ VolatileBufferPtr& operator=(VolatileBuffer* aVBuf) {
+ Set(aVBuf);
+ return *this;
+ }
+
+ VolatileBufferPtr& operator=(VolatileBufferPtr&& aOther) {
+ MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
+ Set(aOther.mVBuf);
+ aOther.Set(nullptr);
+ return *this;
+ }
+
+ private:
+ VolatileBufferPtr(VolatileBufferPtr const& vbufptr) = delete;
+};
+
+} // namespace mozilla
+
+#endif /* mozalloc_VolatileBuffer_h */