diff options
Diffstat (limited to 'memory/volatile')
-rw-r--r-- | memory/volatile/VolatileBuffer.h | 173 | ||||
-rw-r--r-- | memory/volatile/VolatileBufferAshmem.cpp | 139 | ||||
-rw-r--r-- | memory/volatile/VolatileBufferFallback.cpp | 91 | ||||
-rw-r--r-- | memory/volatile/VolatileBufferOSX.cpp | 129 | ||||
-rw-r--r-- | memory/volatile/VolatileBufferWindows.cpp | 160 | ||||
-rw-r--r-- | memory/volatile/moz.build | 31 | ||||
-rw-r--r-- | memory/volatile/tests/TestVolatileBuffer.cpp | 102 | ||||
-rw-r--r-- | memory/volatile/tests/moz.build | 11 |
8 files changed, 836 insertions, 0 deletions
diff --git a/memory/volatile/VolatileBuffer.h b/memory/volatile/VolatileBuffer.h new file mode 100644 index 000000000..ebb471332 --- /dev/null +++ b/memory/volatile/VolatileBuffer.h @@ -0,0 +1,173 @@ +/* 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; + + 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 */ diff --git a/memory/volatile/VolatileBufferAshmem.cpp b/memory/volatile/VolatileBufferAshmem.cpp new file mode 100644 index 000000000..09904d6ef --- /dev/null +++ b/memory/volatile/VolatileBufferAshmem.cpp @@ -0,0 +1,139 @@ +/* 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/. */ + +#include "VolatileBuffer.h" +#include "mozilla/Assertions.h" +#include "mozilla/mozalloc.h" + +#include <fcntl.h> +#include <linux/ashmem.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#ifdef MOZ_MEMORY +extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size); +#endif + +#define MIN_VOLATILE_ALLOC_SIZE 8192 + +namespace mozilla { + +VolatileBuffer::VolatileBuffer() + : mMutex("VolatileBuffer") + , mBuf(nullptr) + , mSize(0) + , mLockCount(0) + , mFd(-1) +{ +} + +bool +VolatileBuffer::Init(size_t aSize, size_t aAlignment) +{ + MOZ_ASSERT(!mSize && !mBuf, "Init called twice"); + MOZ_ASSERT(!(aAlignment % sizeof(void *)), + "Alignment must be multiple of pointer size"); + + mSize = aSize; + if (aSize < MIN_VOLATILE_ALLOC_SIZE) { + goto heap_alloc; + } + + mFd = open("/" ASHMEM_NAME_DEF, O_RDWR); + if (mFd < 0) { + goto heap_alloc; + } + + if (ioctl(mFd, ASHMEM_SET_SIZE, mSize) < 0) { + goto heap_alloc; + } + + mBuf = mmap(nullptr, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0); + if (mBuf != MAP_FAILED) { + return true; + } + +heap_alloc: + mBuf = nullptr; + if (mFd >= 0) { + close(mFd); + mFd = -1; + } + +#ifdef MOZ_MEMORY + posix_memalign(&mBuf, aAlignment, aSize); +#else + mBuf = memalign(aAlignment, aSize); +#endif + return !!mBuf; +} + +VolatileBuffer::~VolatileBuffer() +{ + MOZ_ASSERT(mLockCount == 0, "Being destroyed with non-zero lock count?"); + + if (OnHeap()) { + free(mBuf); + } else { + munmap(mBuf, mSize); + close(mFd); + } +} + +bool +VolatileBuffer::Lock(void** aBuf) +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer"); + + *aBuf = mBuf; + if (++mLockCount > 1 || OnHeap()) { + return true; + } + + // Zero offset and zero length means we want to pin/unpin the entire thing. + struct ashmem_pin pin = { 0, 0 }; + return ioctl(mFd, ASHMEM_PIN, &pin) == ASHMEM_NOT_PURGED; +} + +void +VolatileBuffer::Unlock() +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!"); + if (--mLockCount || OnHeap()) { + return; + } + + struct ashmem_pin pin = { 0, 0 }; + ioctl(mFd, ASHMEM_UNPIN, &pin); +} + +bool +VolatileBuffer::OnHeap() const +{ + return mFd < 0; +} + +size_t +VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + return OnHeap() ? aMallocSizeOf(mBuf) : 0; +} + +size_t +VolatileBuffer::NonHeapSizeOfExcludingThis() const +{ + if (OnHeap()) { + return 0; + } + + return (mSize + (PAGE_SIZE - 1)) & PAGE_MASK; +} + +} // namespace mozilla diff --git a/memory/volatile/VolatileBufferFallback.cpp b/memory/volatile/VolatileBufferFallback.cpp new file mode 100644 index 000000000..f4bfe39c6 --- /dev/null +++ b/memory/volatile/VolatileBufferFallback.cpp @@ -0,0 +1,91 @@ +/* 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/. */ + +#include "VolatileBuffer.h" +#include "mozilla/Assertions.h" +#include "mozilla/mozalloc.h" + +#ifdef MOZ_MEMORY +int posix_memalign(void** memptr, size_t alignment, size_t size); +#endif + +namespace mozilla { + +VolatileBuffer::VolatileBuffer() + : mMutex("VolatileBuffer") + , mBuf(nullptr) + , mSize(0) + , mLockCount(0) +{ +} + +bool VolatileBuffer::Init(size_t aSize, size_t aAlignment) +{ + MOZ_ASSERT(!mSize && !mBuf, "Init called twice"); + MOZ_ASSERT(!(aAlignment % sizeof(void *)), + "Alignment must be multiple of pointer size"); + + mSize = aSize; +#if defined(MOZ_MEMORY) + if (posix_memalign(&mBuf, aAlignment, aSize) != 0) { + return false; + } +#elif defined(HAVE_POSIX_MEMALIGN) + if (moz_posix_memalign(&mBuf, aAlignment, aSize) != 0) { + return false; + } +#else +#error "No memalign implementation found" +#endif + return !!mBuf; +} + +VolatileBuffer::~VolatileBuffer() +{ + MOZ_ASSERT(mLockCount == 0, "Being destroyed with non-zero lock count?"); + + free(mBuf); +} + +bool +VolatileBuffer::Lock(void** aBuf) +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer"); + + *aBuf = mBuf; + mLockCount++; + + return true; +} + +void +VolatileBuffer::Unlock() +{ + MutexAutoLock lock(mMutex); + + mLockCount--; + MOZ_ASSERT(mLockCount >= 0, "VolatileBuffer unlocked too many times!"); +} + +bool +VolatileBuffer::OnHeap() const +{ + return true; +} + +size_t +VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + return aMallocSizeOf(mBuf); +} + +size_t +VolatileBuffer::NonHeapSizeOfExcludingThis() const +{ + return 0; +} + +} // namespace mozilla diff --git a/memory/volatile/VolatileBufferOSX.cpp b/memory/volatile/VolatileBufferOSX.cpp new file mode 100644 index 000000000..af39bcae1 --- /dev/null +++ b/memory/volatile/VolatileBufferOSX.cpp @@ -0,0 +1,129 @@ +/* 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/. */ + +#include "VolatileBuffer.h" +#include "mozilla/Assertions.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/mozalloc.h" + +#include <mach/mach.h> +#include <sys/mman.h> +#include <unistd.h> + +#define MIN_VOLATILE_ALLOC_SIZE 8192 + +namespace mozilla { + +VolatileBuffer::VolatileBuffer() + : mMutex("VolatileBuffer") + , mBuf(nullptr) + , mSize(0) + , mLockCount(0) + , mHeap(false) +{ +} + +bool +VolatileBuffer::Init(size_t aSize, size_t aAlignment) +{ + MOZ_ASSERT(!mSize && !mBuf, "Init called twice"); + MOZ_ASSERT(!(aAlignment % sizeof(void *)), + "Alignment must be multiple of pointer size"); + + mSize = aSize; + + kern_return_t ret = 0; + if (aSize < MIN_VOLATILE_ALLOC_SIZE) { + goto heap_alloc; + } + + ret = vm_allocate(mach_task_self(), + (vm_address_t*)&mBuf, + mSize, + VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); + if (ret == KERN_SUCCESS) { + return true; + } + +heap_alloc: + (void)moz_posix_memalign(&mBuf, aAlignment, aSize); + mHeap = true; + return !!mBuf; +} + +VolatileBuffer::~VolatileBuffer() +{ + MOZ_ASSERT(mLockCount == 0, "Being destroyed with non-zero lock count?"); + + if (OnHeap()) { + free(mBuf); + } else { + vm_deallocate(mach_task_self(), (vm_address_t)mBuf, mSize); + } +} + +bool +VolatileBuffer::Lock(void** aBuf) +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer"); + + *aBuf = mBuf; + if (++mLockCount > 1 || OnHeap()) { + return true; + } + + int state = VM_PURGABLE_NONVOLATILE; + kern_return_t ret = + vm_purgable_control(mach_task_self(), + (vm_address_t)mBuf, + VM_PURGABLE_SET_STATE, + &state); + return ret == KERN_SUCCESS && !(state & VM_PURGABLE_EMPTY); +} + +void +VolatileBuffer::Unlock() +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!"); + if (--mLockCount || OnHeap()) { + return; + } + + int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; + DebugOnly<kern_return_t> ret = + vm_purgable_control(mach_task_self(), + (vm_address_t)mBuf, + VM_PURGABLE_SET_STATE, + &state); + MOZ_ASSERT(ret == KERN_SUCCESS, "Failed to set buffer as purgable"); +} + +bool +VolatileBuffer::OnHeap() const +{ + return mHeap; +} + +size_t +VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + return OnHeap() ? aMallocSizeOf(mBuf) : 0; +} + +size_t +VolatileBuffer::NonHeapSizeOfExcludingThis() const +{ + if (OnHeap()) { + return 0; + } + + unsigned long pagemask = getpagesize() - 1; + return (mSize + pagemask) & ~pagemask; +} + +} // namespace mozilla diff --git a/memory/volatile/VolatileBufferWindows.cpp b/memory/volatile/VolatileBufferWindows.cpp new file mode 100644 index 000000000..b12e0eccb --- /dev/null +++ b/memory/volatile/VolatileBufferWindows.cpp @@ -0,0 +1,160 @@ +/* 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/. */ + +#include "VolatileBuffer.h" +#include "mozilla/Assertions.h" +#include "mozilla/mozalloc.h" +#include "mozilla/WindowsVersion.h" + +#include <windows.h> + +#ifdef MOZ_MEMORY +extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size); +#endif + +#ifndef MEM_RESET_UNDO +#define MEM_RESET_UNDO 0x1000000 +#endif + +#define MIN_VOLATILE_ALLOC_SIZE 8192 + +namespace mozilla { + +VolatileBuffer::VolatileBuffer() + : mMutex("VolatileBuffer") + , mBuf(nullptr) + , mSize(0) + , mLockCount(0) + , mHeap(false) + , mFirstLock(true) +{ +} + +bool +VolatileBuffer::Init(size_t aSize, size_t aAlignment) +{ + MOZ_ASSERT(!mSize && !mBuf, "Init called twice"); + MOZ_ASSERT(!(aAlignment % sizeof(void *)), + "Alignment must be multiple of pointer size"); + + mSize = aSize; + if (aSize < MIN_VOLATILE_ALLOC_SIZE) { + goto heap_alloc; + } + + static bool sUndoSupported = IsWin8OrLater(); + if (!sUndoSupported) { + goto heap_alloc; + } + + mBuf = VirtualAllocEx(GetCurrentProcess(), + nullptr, + mSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + if (mBuf) { + return true; + } + +heap_alloc: +#ifdef MOZ_MEMORY + posix_memalign(&mBuf, aAlignment, aSize); +#else + mBuf = _aligned_malloc(aSize, aAlignment); +#endif + mHeap = true; + return !!mBuf; +} + +VolatileBuffer::~VolatileBuffer() +{ + MOZ_ASSERT(mLockCount == 0, "Being destroyed with non-zero lock count?"); + + if (OnHeap()) { +#ifdef MOZ_MEMORY + free(mBuf); +#else + _aligned_free(mBuf); +#endif + } else { + VirtualFreeEx(GetCurrentProcess(), mBuf, 0, MEM_RELEASE); + } +} + +bool +VolatileBuffer::Lock(void** aBuf) +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer"); + + *aBuf = mBuf; + if (++mLockCount > 1 || OnHeap()) { + return true; + } + + // MEM_RESET_UNDO's behavior is undefined when called on memory that + // hasn't been MEM_RESET. + if (mFirstLock) { + mFirstLock = false; + return true; + } + + void* addr = VirtualAllocEx(GetCurrentProcess(), + mBuf, + mSize, + MEM_RESET_UNDO, + PAGE_READWRITE); + return !!addr; +} + +void +VolatileBuffer::Unlock() +{ + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!"); + if (--mLockCount || OnHeap()) { + return; + } + + void* addr = VirtualAllocEx(GetCurrentProcess(), + mBuf, + mSize, + MEM_RESET, + PAGE_READWRITE); + MOZ_ASSERT(addr, "Failed to MEM_RESET"); +} + +bool +VolatileBuffer::OnHeap() const +{ + return mHeap; +} + +size_t +VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + if (OnHeap()) { +#ifdef MOZ_MEMORY + return aMallocSizeOf(mBuf); +#else + return mSize; +#endif + } + + return 0; +} + +size_t +VolatileBuffer::NonHeapSizeOfExcludingThis() const +{ + if (OnHeap()) { + return 0; + } + + return (mSize + 4095) & ~4095; +} + +} // namespace mozilla diff --git a/memory/volatile/moz.build b/memory/volatile/moz.build new file mode 100644 index 000000000..deacdf433 --- /dev/null +++ b/memory/volatile/moz.build @@ -0,0 +1,31 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. +NO_VISIBILITY_FLAGS = True + +EXPORTS.mozilla += [ + 'VolatileBuffer.h', +] + +if CONFIG['OS_TARGET'] == 'Android': + UNIFIED_SOURCES += [ + 'VolatileBufferAshmem.cpp', + ] +elif CONFIG['OS_TARGET'] == 'Darwin': + UNIFIED_SOURCES += [ + 'VolatileBufferOSX.cpp', + ] +elif CONFIG['OS_TARGET'] == 'WINNT': + UNIFIED_SOURCES += [ + 'VolatileBufferWindows.cpp', + ] +else: + UNIFIED_SOURCES += [ + 'VolatileBufferFallback.cpp', + ] + +FINAL_LIBRARY = 'xul' + +TEST_DIRS += ['tests'] diff --git a/memory/volatile/tests/TestVolatileBuffer.cpp b/memory/volatile/tests/TestVolatileBuffer.cpp new file mode 100644 index 000000000..9a4a8781d --- /dev/null +++ b/memory/volatile/tests/TestVolatileBuffer.cpp @@ -0,0 +1,102 @@ +/* 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/. */ + +#include "gtest/gtest.h" +#include "mozilla/VolatileBuffer.h" +#include <string.h> + +#if defined(ANDROID) +#include <fcntl.h> +#include <linux/ashmem.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#elif defined(XP_DARWIN) +#include <mach/mach.h> +#endif + +using namespace mozilla; + +TEST(VolatileBufferTest, HeapVolatileBuffersWork) +{ + RefPtr<VolatileBuffer> heapbuf = new VolatileBuffer(); + + ASSERT_TRUE(heapbuf) << "Failed to create VolatileBuffer"; + ASSERT_TRUE(heapbuf->Init(512)) << "Failed to initialize VolatileBuffer"; + + VolatileBufferPtr<char> ptr(heapbuf); + + EXPECT_FALSE(ptr.WasBufferPurged()) + << "Buffer should not be purged immediately after initialization"; + EXPECT_TRUE(ptr) << "Couldn't get pointer from VolatileBufferPtr"; +} + +TEST(VolatileBufferTest, RealVolatileBuffersWork) +{ + RefPtr<VolatileBuffer> buf = new VolatileBuffer(); + + ASSERT_TRUE(buf) << "Failed to create VolatileBuffer"; + ASSERT_TRUE(buf->Init(16384)) << "Failed to initialize VolatileBuffer"; + + const char teststr[] = "foobar"; + + { + VolatileBufferPtr<char> ptr(buf); + + EXPECT_FALSE(ptr.WasBufferPurged()) + << "Buffer should not be purged immediately after initialization"; + EXPECT_TRUE(ptr) << "Couldn't get pointer from VolatileBufferPtr"; + + { + VolatileBufferPtr<char> ptr2(buf); + + EXPECT_FALSE(ptr.WasBufferPurged()) + << "Failed to lock buffer again while currently locked"; + ASSERT_TRUE(ptr2) << "Didn't get a pointer on the second lock"; + + strcpy(ptr2, teststr); + } + } + + { + VolatileBufferPtr<char> ptr(buf); + + EXPECT_FALSE(ptr.WasBufferPurged()) + << "Buffer was immediately purged after unlock"; + EXPECT_STREQ(ptr, teststr) << "Buffer failed to retain data after unlock"; + } + + // Test purging if we know how to +#if defined(MOZ_WIDGET_GONK) + // This also works on Android, but we need root. + int fd = open("/" ASHMEM_NAME_DEF, O_RDWR); + + ASSERT_GE(fd, 0) << "Failed to open ashmem device"; + ASSERT_GE(ioctl(fd, ASHMEM_PURGE_ALL_CACHES, NULL), 0) + << "Failed to purge ashmem caches"; +#elif defined(XP_DARWIN) + int state; + vm_purgable_control(mach_task_self(), (vm_address_t)NULL, + VM_PURGABLE_PURGE_ALL, &state); +#else + return; +#endif + + EXPECT_GT(buf->NonHeapSizeOfExcludingThis(), 0ul) + << "Buffer should not be allocated on heap"; + + { + VolatileBufferPtr<char> ptr(buf); + + EXPECT_TRUE(ptr.WasBufferPurged()) + << "Buffer should not be unpurged after forced purge"; + EXPECT_STRNE(ptr, teststr) << "Purge did not actually purge data"; + } + + { + VolatileBufferPtr<char> ptr(buf); + + EXPECT_FALSE(ptr.WasBufferPurged()) << "Buffer still purged after lock"; + } +} diff --git a/memory/volatile/tests/moz.build b/memory/volatile/tests/moz.build new file mode 100644 index 000000000..eea962e71 --- /dev/null +++ b/memory/volatile/tests/moz.build @@ -0,0 +1,11 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES = [ + 'TestVolatileBuffer.cpp', +] + +FINAL_LIBRARY = 'xul-gtest' |